Hadoop: MapReduce的工作流程
1 剖析MapReduce作业运行机制
1.1 过程涉及的实体
- 客户端,提交MapReduce作业;
- YARN资源管理器,负责协调集群上计算机资源的分配;
- YARN节点管理器,负责启动和监视集群中机器上的计算容器(container);
- MapReduce的application master,负责协调运行MapReduce作业的任务。它和MapReduce任务在容器中运行,这些容器由资源管理器分配并由节点管理器进行管理。
- 分布式文件系统,用来和其他实体间共享作业文件。
1.2 作业流程
- 作业的提交;
- 作业的初始化;
- 任务的分配;
- 任务的执行;
- 进度和状态的更新;
- 作业的完成
1.2.1 作业的提交;
- Jobsummiter向资源管理器请求一个应用ID,用于MapReduce作业;
- 检查作业的输出说明,若未指定输出目录或输出目录已存在,则先不提交作业,错误抛回给MapReduce程序;
- 计算作业的输入分片,若由于某些原因(比如指定的输入路径不存在)导致无法计算分片,错误抛回给MapReduce程序;
- 将运行作业所需要的资源(包括JAR文件,配置文件和计算所得的输入分片)复制到一个以作业ID命名的目录下的共享文件系统中。作业JAR的复本较多(由mapreduce.client.submit.file.replication属性控制),因此在运行作业的任务时,集群中有很多个复本可供节点管理器访问;
- 通过调用资源管理器的submitApplication()方法提交作业。
1.2.2 作业的初始化
- 资源管理器收到submitApplication()消息后,便将请求传递给YARN调度器(scheduler);
- 调度器分配一个容器,然后资源管理器在节点管理器的管理下在容器中启动application master;
- application master对作业进行初始化:通过创建多个薄记对象以保持对作业进度的跟踪来完成的;
- 接受来自共享文件系统的输入分片;
- 对每一个分片创建一个map任务以及确定多个reduce对象,分配任务id;
1.2.3 任务的分配
- application master为作业的所有map任务和reduce任务向资源管理器请求容器。
- 首先为Map任务发出请求,高于reduce任务请求。因为所有的map任务必须在reduce的排序阶段能够启动前完成。
- 请求为任务指定内存需求和CPU数。
1.2.4 任务的执行
- 通过与节点管理器通信来启动容器,在这之前完成任务所需资源的本地化,包括作业的配置文件和缓存文件等。
1.2.5 进度和状态的更新
- 输出已处理输入所占比例;
- 输出进度报告。
1.2.6 作业的完成
2 shuffle和排序
将map输出作为输入传给reduce的过程叫做shuffle。
2.1 map端
2.1.1 环形缓冲区
map函数开始输出时并不是简单的写到磁盘,每个map任务都有一个环形内存缓冲区用于存储任务输出。在默认情况下,缓冲区的大小为100MB,可通过mapreduce.task.io.sort.mb属性调整,当缓冲区内容达到阈值,一个后台线程便开始把内容溢出到磁盘,在溢出写到磁盘过程中,map输出继续写道缓冲区,但如果在此期间缓冲区被填满,map会被阻塞直到写磁盘过程完成。
2.1.2 写磁盘前的分区
写磁盘之前,线程会根据最终的reducer把数据划分为相应的分区,在每个分区中后台线程按键进行内存中排序,如果有一个combiner函数,它就在排序后的输出上运行,这会使得map输出结果更紧凑,因此减少磁盘的数据写入和传输。
2.1.3 合并溢出文件
在map任务写完其最后一个输出记录之后,会对溢出文件进行合并成已分区且排序的输出文件,配置属性mapreduce.task.io.sort.factor控制一次合并多少,默认为10;
2.2 reduce端
- 运行map任务的tasktraker需要为分区运行其reduce任务,并且reduce任务需要集群上若干个map任务的map输出作为特殊的分区文件,每个map任务完成时,reduce任务就开始复制其输出,这就是reduce任务的复制阶段。控制复制线程数量的设置是mapreduce.reduce.shuffle.parallecopies属性。
- 复制完所有map输出后,reduce任务进入到合并阶段。这个阶段将合并map输出,维持其顺序排序,这是循环进行的。
2.3 mapreduce配置调优
2.3.1 map端调优属性
- 内存缓冲区大小mapreduce.task.io.sort.mb;
- 内存缓冲区溢出阈值 mapreduce.map.sort.spill.percent;
- 排序文件合并文件个数 mapreduce.task.io.sort.factor;
- 运行combine所需最少溢出文件数 mapreduce.map.combine.minspills;
- 是否压缩map输出 mapreduce.map.output.compress;
2.3.2 reduce端调优属性
- mapreduce.reduce.shuffle.parallelcopies,复制map输出的线程数;
- mapreduce.reduce.shuffle.maxfetchfailures, 声明失败前获取一个map文件reducer所花的最大时间;
- mapreduce.task.io.sort.factor;
- mapreduce.reduce.shuffle.input.buffer.percent shuffle复制阶段分配给map输出的缓冲区占堆空间的百分比;
- mapreduce.reduce.shuffle.merge.percent, map输出缓冲区阈值,用于合并输出和磁盘溢出的过程;
- mapreduce.reduce.merge.inmem.threshold 合并输出和磁盘溢出写过程的map输出的阈值数,0或者更小的数意味着没有阈值限制。