合理设置 Map Reduce


1 通常情况下,作业会通过 input 的目录产生一个或者多个 map 任务。



主要的决定因素有: input 的文件总个数, input 的文件大小,集群设置的文件块大小。



2 是不是 map 数越多越好?



答案是否定的。如果一个任务有很多小文件(远远小于块大小 128m ),则每个小文件



也会被当做一个块,用一个 map 任务来完成,而一个 map 任务启动和初始化的时间远远大



于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的 map 数是受限的。



3 是不是保证每个 map 处理接近 128m 的文件块,就高枕无忧了?



答案也是不一定。比如有一个 127m 的文件,正常会用一个 map 去完成,但这个文件只



有一个或者两个小字段,却有几千万的记录,如果 map 处理的逻辑比较复杂,用一个 map



任务去做,肯定也比较耗时。



针对上面的问题 2 和 3 ,我们需要采取两种方式来解决:即减少 map 数和增加 map 数;




5.1 复杂文件增加 Map




当 input 的文件都很大,任务逻辑复杂, map 执行非常慢的时候,可以考虑增加 Map 数,



来使得每个 map 处理的数据量减少,从而提高任务的执行效率。



增加 map 的方法为:根据



computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M 公式,



调整 maxSize 最大值。让 maxSize 最大值低于 blocksize 就可以增加 map 的个数。



案例实操:




1 )执行查询




hive map数过多 hive map数量由什么决定_hive map数过多


2)设置最大切片值为 100 个字节


hive map数过多 hive map数量由什么决定_hadoop_02


5.2 小文件进行合并


1 在 map 执行前合并小文件,减少 map 数: CombineHiveInputFormat 具有对小文件进行合


并的功能(系统默认的格式)。 HiveInputFormat 没有对小文件合并功能。


set hive.input.format=


org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;


2 在 Map-Reduce 的任务结束时合并小文件的设置:


在 map-only 任务结束时合并小文件,默认 true


SET hive.merge.mapfiles = true;


在 map-reduce 任务结束时合并小文件,默认 false


SET hive.merge.mapredfiles = true;


合并文件的大小,默认 256M


SET hive.merge.size.per.task = 268435456;


当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge


SET hive.merge.smallfiles.avgsize = 16777216;


5.3 合理设置 Reduce


1 )调整 reduce 个数方法一


(1)每个 Reduce 处理的数据量默认是 256MB


hive.exec.reducers.bytes.per.reducer=256000000


(2)每个任务最大的 reduce 数,默认为 1009


hive.exec.reducers.max=1009


(3)计算 reducer 数的公式


N=min( 参数 2 ,总输入数据量 / 参数 1)


2 )调整 reduce 个数方法二


在 hadoop 的 mapred-default.xml 文件中修改


设置每个 job 的 Reduce 个数


set mapreduce.job.reduces = 15;


3 reduce 个数并不是越多越好


(1)过多的启动和初始化 reduce 也会消耗时间和资源;


(2)另外,有多少个 reduce ,就会有多少个输出文件,如果生成了很多个小文件,那


么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;


在设置 reduce 个数的时候也需要考虑这两个原则:处理大数据量利用合适的 reduce 数;


使单个 reduce 任务处理数据量大小要合适;


并行执行


Hive 会将一个查询转化成一个或者多个阶段。这样的阶段可以是 MapReduce 阶段、抽


样阶段、合并阶段、 limit 阶段。或者 Hive 执行过程中可能需要的其他阶段。默认情况下,


Hive 一次只会执行一个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能


并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行


时间缩短。不过,如果有更多的阶段可以并行执行,那么 job 可能就越快完成。


通过设置参数 hive.exec.parallel 值为 true ,就可以开启并发执行。不过,在共享集群中,


需要注意下,如果 job 中并行阶段增多,那么集群利用率就会增加。


set hive.exec.parallel=true; // 打开任务并行执行


set hive.exec.parallel.thread.number=16; // 同一个 sql 允许最大并行度,默认为


8 。


当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。


7 严格模式


Hive 可以通过设置防止一些危险操作:


1 )分区表不使用分区过滤


将 hive.strict.checks.no.partition.filter 设置为 true 时,对于分区表, 除非 where 语句中含


有分区字段过滤条件来限制范围,否则不允许执行。 换句话说,就是用户不允许扫描所有分


区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有


进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。


2 )使用 order by 没有 limit 过滤


将 hive.strict.checks.orderby.no.limit 设置为 true 时,对于 使用了 order by 语句的查询,要


求必须使用 limit 语句。 因为 order by 为了执行排序过程会将所有的结果数据分发到同一个


Reducer 中进行处理,强制要求用户增加这个 LIMIT 语句可以防止 Reducer 额外执行很长一


段时间。


3 )笛卡尔积


将 hive.strict.checks.cartesian.product 设置为 true 时, 会限制笛卡尔积的查询。 对关系型数


据库非常了解的用户可能期望在 执行 JOIN 查询的时候不使用 ON 语句而是使用 where 语


句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸


的是, Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情


况。


10.8 JVM 重用