1.1 MapTask 并行度
MapTask 并行度决定 Map 阶段的任务处理并发度,进而影响到整个 Job 的处理速度。
那么, MapTask 并行实例是否越多越好呢?其并行度又是如何决定呢?
一个 Job 的 Map 阶段并行度由客户端在提交 Job 时决定, 客户端对 Map 阶段并行度的规划的基本逻辑为:
将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个 split),然后每一个 split 分配一个 MapTask 并行实例处理。
这段逻辑及形成的切片规划描述文件,是由 FileInputFormat 实现类的 getSplits()
方法完成的。该方法返回的是 List
, InputSplit 封装了每一个逻辑切片的信息,包括长度和位置信息,而 getSplits()
方法返回一组 InputSplit。
1.2 FileInputFormat 切片机制
1. FileInputFormat 中默认的切片机制:
(1)简单地按照文件的内容长度进行切片
(2)切片大小,默认等于 block 大小
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
比如待处理数据有两个文件:
File1.txt 200M
File2.txt 100M
经过 getSplits()
方法处理之后,形成的切片信息是:
File1.txt-split1 0-128M
File1.txt-split2 129M-200M
File2.txt-split1 0-100M
2. FileInputFormat 中切片的大小的参数配置:
计算切片大小:long splitSize = computeSplitSize(Math.max(minSize, Math.min(maxSize, blockSize))),翻译一下就是求这三个值的中间值。
切片主要由这几个值来运算决定:
dfs.blocksize
修改mapreduce.input.fileinputformat.split.minsize
修改mapreduce.input.fileinputformat.split.maxsize
修改因此, 默认情况下,切片大小等于 blocksize。
ReduceTask 的并行度同样影响整个 Job 的执行并发度和执行效率,但与 MapTask 的并发数由切片数决定不同, ReduceTask 数量的决定是可以直接手动设置:
job.setNumReduceTasks(4); //默认值是 1,手动设置为 4
ReduceTask 的数量默认为 1,我们手动设置为 4,表示运行 4 个 ReduceTask,相应的输出结果会有4个,如下图所示:
图16
如果设置为 0,表示不运行 ReduceTask 任务,也就是没有 Reduce 阶段,只有 Map 阶段,Map 阶段的输出结果作为最终的输出结果。
如果数据分布不均匀,就有可能在 Reduce 阶段产生数据倾斜。
注意: ReduceTask 数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有 1 个 ReduceTask。
3.1 MapReduce 结构
一个完整的 MapReduce 程序在分布式运行时有两类实例进程:
以上两个阶段 MapTask 和 ReduceTask 的进程都是 YarnChild,并不是说这 MapTask 和 ReduceTask 就跑在同一个 YarnChild 进程里。
运行任意一个 MapReduce 程序,使用jps
命令查看进程:
图1
从图中可以看出,MapReduce 运行时,开启了 MRAppMaster 和 YarnChild 进程,此图中的 YarnChild 代表的是 MapTask。运行完 MapTask 阶段,此 YarnChild 进程会关闭,随后再运行 ReduceTask 阶段,此时还会开启一个名为 YarnChild 的进程,但是通过查看进程号发现,此时的 YarnChild 进程是一个新的进程,与 MapTask 阶段的 YarnChild 不是同一个进程,如下图所示:
图2
3.2 MapReduce 程序的运行流程
1. 一个 MapReduce 程序启动的时候,最先启动的是 MRAppMaster, MRAppMaster 启动后根据本次 Job 的描述信息,计算出需要的 MapTask 实例数量,然后向集群申请机器启动相应数量的 MapTask 进程;
2. MapTask 进程启动之后,根据给定的数据切片(哪个文件的哪个偏移量范围)范围进行数据处理,主体流程为:
map()
方法,做逻辑运算,并将 map()
方法输出的 KV 对收集到缓存 3. MRAppMaster 监控到所有 MapTask 进程任务完成之后(真实情况是,某些 MapTask 进程处理完成后,就会开始启动 ReduceTask 去已完成的 MapTask 处 fetch 数据),会根据客户指定的参数启动相应数量的 ReduceTask 进程,并告知 ReduceTask 进程要处理的数据范围(数据分区);
4. ReduceTask 进程启动之后,根据 MRAppMaster 告知的待处理数据所在位置,从若干台 MapTask 运行所在机器上获取到若干个 MapTask 输出结果文件,并在本地进行重新归并排序,然后按照相同 key 的 KV 为一个组,调用客户定义的 reduce()
方法进行逻辑运算,并收集运算输出的结果 KV,然后调用客户指定的 OutputFormat 将结果数据输出到外部存储。
总结 WordCount 程序的详细实现流程:
图3