前言
Hadoop的三个核心模块:HDFS、MapReduce(简称MR)和Yarn,其中HDFS模块负责数据存储,MapReduce负责数据计算,Yarn负责计算过程中的资源调度。在存算分离的架构中,三者越来越多的同其他框架搭配使用,如用Spark替代MapReduce作为计算引擎或者k8s替换Yarn作为资源调度工作。虽然已经有了许多替代框架,MapReduce的计算原理仍具有重要意义,掌握MR对于学习其他计算框架甚至自研计算框架,都非常有帮助。
基本知识
本文涉及的名词解释
- Hadoop:大数据存储计算框架,核心包括HDFS、MapReduce和Yarn
- HDFS:分布式文件系统,包括
- namenode:存储系统主节点,存储数据库的存储信息
- datanode:负责数据块的实际存储
- MapReduce: 分布式计算引擎,包括mapper、reducer、shuffle等过程;
- Yarn:资源调度框架,由ResourceManager、NodeManager、ApplicationMaster、Container、Scheduler 等几个组件构成
- ResourceManager:全局的资源管理器,负责整个系统的资源管理
- NodeManager:每个计算节点上的资源和任务管理器
- ApplicationMaster:每个应用程序的管理器,管理由ResourceManager分配的NodeManager节点
- Container:NodeManager节点中内存、CPU等资源的抽象
- Scheduler:调度器,负责应用程序的运行顺序等
MapReduce工作流程
任务提交(Yarn)
流程图
该部分主要由客户端和Yarn交互,包括任务的提交、资源申请分配、启动maptask:
- 客户端提交MR程序至集群,由YarnRunner向ResourceManager申请创建任务job;
- ResourceManager同意创建job,并返回资源提交路径;
- 客户端提交job运行所需资源,包括执行程序、配置信息和文件切片信息;
- 资源提交后,向ResourceManager申请创建ApplicationMaster;
- ResourceManager根据请求创建一个task,并分配至一个nodemanager中;
- NodeManager领取到task后,创建Container,创建ApplicationMaster,下载job运行资源至本地;
- ApplicationMaster根据切片信息,向ResourceManager申请运行MapTask;
- ResourceManager分配MapTask任务至NodeManager,NodeManager领取任务,创建Container。ResourceManager将分配信息返回ApplicationMaster;
- ApplicationMaster向NodeManager发送程序,NodeManager启动MapTask,开始执行计算。
任务计算(MapReduce)
流程图1 - mapper流程
流程2 - reducer
- ResourceManager根据客户端请求,根据切片信息,计算出MapTask数量;默认根据块大小切分,小于块大小的文件单独占用一个maptask;
- NodeManager启动MapTask进程,MapTask开始读取文件,默认采用TextInputFormat格式读取,即一次读取一行,(k,v)形式,K表示一行文本,v表示每行的偏移量;
- 对读取数据进行逻辑运算,针对每行数据调用map方法,在map方法内数据处理,并调用context.write方法将数据写出至环形缓冲区;
- 数据以<k, v>形式写入环形缓冲区。环形缓冲区为内存中一块区域,默认100m,mapper写出的数据会先写入环形缓冲区,再写至磁盘,以减少IO次数。环形缓冲区分为2个部分,分布存放索引和数据;
- 当环形缓冲区达到80%时,数据溢写至磁盘中。在溢写之前,针对数据进行分区内排序,排序方法为快排。如果用户定义了Combiner,在溢写磁盘前,数据将先进行combiner计算;
- 数据将写至磁盘,每次溢写,产生索引和数据2个文件;
- 当前mapper处理完数据后,针对磁盘中产生的多个溢写文件进行合并,由于每个文件内数据已经有序,在合并时采用归并排序方法合并,并产生最终一个合并后的文件。如果用户定义了combiner,合并后的文件将再次执行combiner计算。最终产生一个索引文件和一个数据文件,数据文件包含多个分区,每个分区内数据有序,索引文件记录不同分区位置信息;分区个数等于reducer个数,reducer个数在程序中指定,默认为1;
- 待所有mapper运行完毕后,由appmaster统计reducer,告知可以开始运行。如开启了推测运行,则reducer可以不等所有mapper运行完,可提前开始运行;reducer访问mapper,根据索引文件,读取数据文件中对应分区的数据。如文件较多或数据较大,数据将缓存至磁盘上;
- 从mapper fetch数据后,将针对多个文件进行一次归并排序合并文件,相同分区的数据放在一起并分区内有序;
- 执行reducer中reduce方法,相同key的记录会进入同一个reduce方法进行处理,最后调用context.write方法将数据写出;
- 数据默认写出至程序指定的目录中,默认输出数据格式为TextOutputFormat。
至此,整个mr计算过程完成。
相关优化
小文件
缺点:小文件过多会导致每个mapper处理数据较少,mapper的处理时间小于启动的时间,无法充分发挥mapper的效率,造成资源浪费;
优化:将默认的textinputformat改为combineinputformat,合并读取的小文件。
shuffle
缺点:shuffle是mr整个流程中比较占性能的环节,涉及大量数据排序、落盘以及网络传输,往往程序的性能瓶颈出现在这个环节。
优化:1. 避免shuffle,如开启map端join;2. 减少shuffle处理数据量,如自定义combiner开启mapper端聚合,但是要注意mapper端聚合不能影响最终结果;3. 优化默认参数配置,如调整环形缓冲区大小、溢出阈值、提高maptask堆内存等。
mapper与reducer并行度
缺点:要合理设置mapper与reducer数量,过多容易造成资源浪费,小文件过多,过少则并行度不佳,难以发挥大数据的优势。
优化:1. 默认采用块大小(dfs.block.size)作为分片切分,针对CPU密集型任务,则适当降低每个mapper的数据量(设置mapred.max.split.size为较小值);2. 通过setNumReduceTasks设置reduce数量,如果不需要reduce过程,则设置为0;