7.5 MapReduce程序的核心运行机制

任务目的

  • 知晓客户端对 Map 阶段并行度的规划
  • 掌握 FileInputFormat 的默认切片机制
  • 掌握手动设置 ReduceTask 数量的方法
  • 理解 MapReduce 程序的运行流程

任务清单

  • 任务1:MapTask 并行度决定机制
  • 任务2:ReduceTask 并行度决定机制
  • 任务3:MapReduce 程序的运行流程

详细任务步骤

任务1:MapTask 并行度决定机制

1.1 MapTask 并行度

  MapTask 并行度决定 Map 阶段的任务处理并发度,进而影响到整个 Job 的处理速度。

  那么, MapTask 并行实例是否越多越好呢?其并行度又是如何决定呢?

  一个 Job 的 Map 阶段并行度由客户端在提交 Job 时决定, 客户端对 Map 阶段并行度的规划的基本逻辑为:

  将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个 split),然后每一个 split 分配一个 MapTask 并行实例处理。

  这段逻辑及形成的切片规划描述文件,是由 FileInputFormat 实现类的 getSplits() 方法完成的。该方法返回的是 List<InputSplit>, 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))),翻译一下就是求这三个值的中间值。

  切片主要由这几个值来运算决定:

  • blocksize: 默认是 128M,可通过 dfs.blocksize 修改
  • minSize: 默认是 1,可通过 mapreduce.input.fileinputformat.split.minsize 修改
  • maxsize: 默认是 Long.MaxValue,可通过mapreduce.input.fileinputformat.split.maxsize 修改

  因此, 默认情况下,切片大小等于 blocksize。

  • 如果 maxsize 调的比 blocksize 小,则切片会小于 blocksize,而且就等于配置的这个参数的值;
  • 如果 minsize 调的比 blocksize 大,则切片会大于 blocksize。
    但是,不论怎么调参数,都不能让多个小文件“划入”一个 split。

任务2:ReduceTask 并行度决定机制

  ReduceTask 的并行度同样影响整个 Job 的执行并发度和执行效率,但与 MapTask 的并发数由切片数决定不同, ReduceTask 数量的决定是可以直接手动设置

job.setNumReduceTasks(4); 	//默认值是 1,手动设置为 4 

  ReduceTask 的数量默认为 1,我们手动设置为 4,表示运行 4 个 ReduceTask,相应的输出结果会有4个,如下图所示:

Vditor

图16

 

  如果设置为 0,表示不运行 ReduceTask 任务,也就是没有 Reduce 阶段,只有 Map 阶段,Map 阶段的输出结果作为最终的输出结果。

  如果数据分布不均匀,就有可能在 Reduce 阶段产生数据倾斜。

  注意: ReduceTask 数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有 1 个 ReduceTask。

任务3:MapReduce 程序的运行流程

3.1 MapReduce 结构

  一个完整的 MapReduce 程序在分布式运行时有两类实例进程:

  • MRAppMaster(MapReduce Application Master):负责整个程序的过程调度及状态协调
  • YarnChild(MapTask):负责 Map 阶段的整个数据处理流程,阶段并发任务
  • YarnChild(ReduceTask):负责 Reduce 阶段的整个数据处理流程,阶段汇总任务

  以上两个阶段 MapTask 和 ReduceTask 的进程都是 YarnChild,并不是说这 MapTask 和 ReduceTask 就跑在同一个 YarnChild 进程里。

  运行任意一个 MapReduce 程序,使用jps命令查看进程:

Vditor

图1

 

  从图中可以看出,MapReduce 运行时,开启了 MRAppMaster 和 YarnChild 进程,此图中的 YarnChild 代表的是 MapTask。运行完 MapTask 阶段,此 YarnChild 进程会关闭,随后再运行 ReduceTask 阶段,此时还会开启一个名为 YarnChild 的进程,但是通过查看进程号发现,此时的 YarnChild 进程是一个新的进程,与 MapTask 阶段的 YarnChild 不是同一个进程,如下图所示:

Vditor

图2

 

3.2 MapReduce 程序的运行流程

  1. 一个 MapReduce 程序启动的时候,最先启动的是 MRAppMaster, MRAppMaster 启动后根据本次 Job 的描述信息,计算出需要的 MapTask 实例数量,然后向集群申请机器启动相应数量的 MapTask 进程;
  2. MapTask 进程启动之后,根据给定的数据切片(哪个文件的哪个偏移量范围)范围进行数据处理,主体流程为:

  • 利用客户指定的 InputFormat 来获取 RecordReader 读取数据,形成输入 KV 对
  • 将输入 KV 对传递给客户定义的 map() 方法,做逻辑运算,并将 map() 方法输出的 KV 对收集到缓存
  • 将缓存中的 KV 对按照 K 分区排序后不断溢写到磁盘文件

  3. MRAppMaster 监控到所有 MapTask 进程任务完成之后(真实情况是,某些 MapTask 进程处理完成后,就会开始启动 ReduceTask 去已完成的 MapTask 处 fetch 数据),会根据客户指定的参数启动相应数量的 ReduceTask 进程,并告知 ReduceTask 进程要处理的数据范围(数据分区);
  
  4. ReduceTask 进程启动之后,根据 MRAppMaster 告知的待处理数据所在位置,从若干台 MapTask 运行所在机器上获取到若干个 MapTask 输出结果文件,并在本地进行重新归并排序,然后按照相同 key 的 KV 为一个组,调用客户定义的 reduce() 方法进行逻辑运算,并收集运算输出的结果 KV,然后调用客户指定的 OutputFormat 将结果数据输出到外部存储。

  总结 WordCount 程序的详细实现流程:

Vditor

图3

猜你喜欢

转载自blog.csdn.net/c_lanxiaofang/article/details/107836972
7.5