MapReduce运行流程
一个完整的MapReduce程序在分布式运行时有三类实例进程:
1) MRAppMaster:负责整个程序的过程调度及状态协调
2) MapTask:负责map阶段的整个数据处理流程
3) ReduceTask:负责reduce阶段的整个数据处理流程
当一个作业提交后(mr程序启动),大概流程如下:
1) 一个mr程序启动的时候,会先启动一个进程Application Master,它的主类是MRAppMaster
2) appmaster启动之后会根据本次job的描述信息,计算出inputSplit的数据,也就是MapTask的数量
3) appmaster然后向resourcemanager来申请对应数量的container来执行MapTask进程。
4) MapTask进程启动之后,根据对应的inputSplit来进行数据处理,处理流程如下
-利用客户指定的inputformat来获取recordReader读取数据,形成kv键值对。
-将kv传递给客户定义的mapper类的map方法,做逻辑运算,并将map方法的输出kv收集到缓存。
-将缓存中的kv数据按照k分区排序后不断的溢出到磁盘文件
5) appmaster监控maptask进程完成之后,会根据用户指定的参数来启动相应的reduceTask进程,并告知reduceTask需要处理的数据范围
6) reducetask启动之后,根据appmaster告知的待处理的未知数据,从若干的已经存到磁盘的数据中拿到数据,并在本地进行一个归并排序,然后,再按照相同的key的kv为一组,调用客户自定义的reduce方法,并收集输出结果kv,然后按照用户指定的outputFormat将结果存储到外部设备。
图示
运行流程之MapTask
1. maptask调用FileInputFormat的getRecordReader读取分片数据
2. 每行数据读取一次,返回一个(K,V)对,K是offset,V是一行数据
3. 将k-v对交给MapTask处理
4. 每对k-v调用一次map(K,V,context)方法,然后context.write(k,v)
5. 写出的数据交给收集器OutputCollector.collector()处理
6. 将数据写入环形缓冲区,并记录写入的起始偏移量,终止偏移量,环形缓冲区默认大小100M
7. 默认写到80%的时候要溢写到磁盘,溢写磁盘的过程中数据继续写入剩余20%
8. 溢写磁盘之前要先进行分区然后分区内进行排序
9. 默认的分区规则是hashpatitioner,即key的hash%reduceNum
10. 默认的排序规则是key的字典顺序,使用的是快速排序
11. 溢写会形成多个文件,在maptask读取完一个分片数据后,先将环形缓冲区数据刷写到磁盘
12. 将数据多个溢写文件进行合并,分区内排序(外部排序===》归并排序)
运行流程之ReduceTask
1. 数据按照分区规则发送到reducetask
2. reducetask将来自多个maptask的数据进行合并,排序(外部排序===》归并排序)
3. 按照key相同分组()
4. 一组数据调用一次reduce(k,iterable<v>values,context)
5. 处理后的数据交由reducetask
6. reducetask调用FileOutputFormat组件
7. FileOutputFormat组件中的write方法将数据写出
shuffle流程总结
1. 从map函数输出到reduce函数接受输入数据,这个过程称之为shuffle.
2. map函数的输出,存储环形缓冲区(默认大小100M,阈值80M)环形缓冲区:其实是一个字节数组kvbuffer. 有一个sequator标记,kv原始数据从左向右填充(顺时针),kvmeta是对kvbuffer的一个封装,封装成了int数组,用于存储kv原始数据的对应的元数据valstart,keystart,partition,vallen信息,从右向左(逆时针)。参考(环形缓冲区的详解一张)
3. 当达到阈值时,准备溢写到本地磁盘(因为是中间数据,因此没有必要存储在HDFS上)。在溢写前要进行对元数据分区(partition)整理,然后进行排序(quick sort,通过元数据找到出key,同一分区的所有key进行排序,排序完,元数据就已经有序了,在溢写时,按照元数据的顺序寻找原始数据进行溢写)
4. 如果有必要,可以在排序后,溢写前调用combiner函数进行运算,来达到减少数据的目的
5. 溢写文件有可能产生多个,然后对这多个溢写文件进行再次合并(也要进行分区和排序)。当溢写个数>=3时,可以再次调用combiner函数来减少数据。如果溢写个数<3时,默认不会调用combiner函数。
6. 合并的最终溢写文件可以使用压缩技术来达到节省磁盘空间和减少向reduce阶段传输数据的目的。(存储在本地磁盘中)
7. Reduce阶段通过HTTP写抓取属于自己的分区的所有map的输出数据(默认线程数是5,因此可以并发抓取)。
8. 抓取到的数据存在内存中,如果数据量大,当达到本地内存的阈值时会进行溢写操作,在溢写前会进行合并和排序(排序阶段),然后写到磁盘中,
9. 溢写文件可能会产生多个,因此在进入reduce之前会再次合并(合并因子是10),最后一次合并要满足10这个因子,同时输入给reduce函数,而不是产生合并文件。reduce函数输出数据会直接存储在HDFS上。