这是一个关于Hive性能调优非常核心的问题。在Hive中,Map和Reduce任务的数量直接决定了作业的执行效率和资源利用率。下面我将详细解释如何设置以及其依据。
一、设置Map任务的数量
Map任务的数量主要取决于输入数据的大小和数量,通常用户无法直接设置一个精确值,但可以通过参数来间接影响。
1. 主要控制参数
-
mapred.map.tasks(Hive 1.x 之前) /mapreduce.job.maps(Hive 2.x+,YARN环境下):- 这个参数只是个期望值,不是强制性的! 最终实际的Map数取决于输入文件的切片(Split)信息。
- 如果
InputFormat生成的切片数大于这个值,则会采用更大的切片数。所以通常这个参数不需要修改。
-
最关键参数:
mapred.max.split.size(决定每个Map处理的最大数据量)- 单个Map任务处理的最大输入数据量。默认值大约是256MB(256 * 1024 * 1024)。
- 计算公式:
Map数量 = max( min(总输入数据大小 / max.split.size, mapred.map.tasks), min.split.size.per.node, ...) - 实际上,Hive会根据
max.split.size、min.split.size.per.node和min.split.size.per.rack等一系列参数来对输入文件进行逻辑切片,每个切片都会启动一个Map任务。
-
mapred.min.split.size: 单个Map任务处理的最小输入数据量。 -
hive.hadoop.supports.splittable.combineinputformat: 是否使用可分割的CombineInputFormat,对于小文件多的场景,开启后(设为true)可以进行合并,减少Map数。
2. 设置依据与原则
-
增加Map数量(调小
mapred.max.split.size):- 场景:当输入文件都很大,且是不可分割的(如gzip压缩的文件),或者集群资源充足,希望提高并发度以更快完成任务时。
- 风险:Map任务过多,任务启动、调度、销毁的开销会增大,可能导致整体性能下降。
-
减少Map数量(调大
mapred.max.split.size):- 场景:输入目录下有大量小文件(比如成千上万个几MB的文件)。每个小文件都会至少生成一个Map任务,导致Map数量爆炸,极大增加NameNode和JobTracker的压力。
- 方法:调大
max.split.size(例如设为1GB),让多个小文件被合并到一个切片中。或者使用Hive的合并小文件功能(set hive.merge.mapfiles = true;)。
总结:Map数的目标通常是让每个Map任务处理接近块大小(128MB或256MB)的数据,同时避免大量小文件的存在。
二、设置Reduce任务的数量
相比于Map任务,Reduce任务的数量可以直接由用户更精确地控制。
1. 主要控制参数
-
mapred.reduce.tasks/mapreduce.job.reduces:- 这是直接设置Reduce任务个数的参数。默认值为-1,表示Hive会自动计算。
- 如果手动设置了这个参数为一个正数,Hive就会使用你指定的Reduce数量。
-
Hive自动计算Reduce数的逻辑(当
mapred.reduce.tasks为默认值-1时):- 计算公式:
reduce_number = min(参数2, 总输入数据量 / 参数1) - 参数1:
hive.exec.reducers.bytes.per.reducer- 每个Reduce任务处理的数据量。默认值约为256MB(256 * 1024 * 1024)。
- 例如,如果总输入数据是5GB,那么Hive会估算出大约需要
5 * 1024 / 256 ≈ 20个Reduce任务。
- 参数2:
hive.exec.reducers.max- 限制Reduce任务的最大数量,防止过度消耗集群资源。默认值是1009。
- 即使根据上一个参数计算出来需要2000个Reduce,实际也会被限制为1009个。
- 计算公式:
2. 设置依据与原则
-
如何设置Reduce数量:
- 自动估算:不设置
mapred.reduce.tasks,让Hive根据bytes.per.reducer和reducers.max自动计算。这在大多数情况下是合理的。 - 手动指定:在SQL脚本中明确设置,例如:
set mapred.reduce.tasks = 50;
- 自动估算:不设置
-
设置依据:
- 增加Reduce数量(调小
bytes.per.reducer或直接设大reduce.tasks):- 场景:数据量大、Key分布均匀、需要提高并发度缩短执行时间。集群资源充足。
- 好处:更好的负载均衡,防止单个Reduce负载过重成为瓶颈。
- 减少Reduce数量(调大
bytes.per.reducer或直接设小reduce.tasks):- 场景:数据量不大;Key分布极度不均,导致少量Reduce接收了大量数据(如使用
count(distinct)时容易发生数据倾斜),此时减少Reduce数可能反而能避免OOM错误。 - 风险:Reduce数过少会导致单个Reduce处理数据量巨大,运行缓慢,且可能无法充分利用集群资源。
- 场景:数据量不大;Key分布极度不均,导致少量Reduce接收了大量数据(如使用
- 增加Reduce数量(调小
-
一个重要的经验值:
- 一个推荐的起点是让每个Reduce任务处理大约1GB左右的数据。你可以根据你的集群规模和数据量调整
hive.exec.reducers.bytes.per.reducer(例如设为1 * 1024 * 1024 * 1024)。 - 观察Reduce任务的执行时间,如果一个Reduce运行了非常久,而其他很早就结束了,说明可能发生了数据倾斜,需要用到**
hive.groupby.skewindata=true**等参数来优化,而不是简单调整Reduce数量。
- 一个推荐的起点是让每个Reduce任务处理大约1GB左右的数据。你可以根据你的集群规模和数据量调整
三、实践建议与示例
-
首先处理小文件问题:在调整任何参数前,先确保没有小文件问题。可以使用
INSERT OVERWRITE ...语句配合适当的mapred.max.split.size或Hive的合并参数(hive.merge.*)来重写数据,使文件大小合理化。 -
优先使用自动计算:除非你有明确理由,否则先让Hive自动计算Map和Reduce的数量,观察作业运行情况。
-
循序渐进地调整:每次只调整一个参数,观察性能变化(如运行时间、资源使用情况),找到最佳配置。
-
常用设置示例:
-- 设置每个Map处理的最大数据为128MB(增加Map数)
SET mapred.max.split.size=134217728;
-- 设置每个Reduce处理的数据为1GB(减少Reduce数)
SET hive.exec.reducers.bytes.per.reducer=1073741824;
-- 直接设置Reduce任务数为50
SET mapred.reduce.tasks=50;
-- 开启任务执行时的合并小文件功能
SET hive.merge.mapfiles=true;
SET hive.merge.mapredfiles=true;
SET hive.merge.size.per.task=256000000; -- 合并后文件的大小
SET hive.merge.smallfiles.avgsize=16000000; -- 当输出文件的平均大小小于该值时,启动一个独立的map-only任务进行文件merge
-- 开启针对GROUP BY操作的数据倾斜优化
SET hive.groupby.skewindata=true;
最终,最佳的设置取决于你的具体数据、集群环境和业务逻辑,需要通过多次测试和监控来找到最优解。 监控YARN的ResourceManager UI或Hive的日志来查看实际生效的Map和Reduce数量是至关重要的调试步骤。

862

被折叠的 条评论
为什么被折叠?



