MapReduce中数据处理详解

来源:互联网 发布:网络短信免费版网页 编辑:程序博客网 时间:2024/05/21 22:55

作业提交阶段


对于每一种InputFormat都会提供两个方法:
getSplits() 用来分片,一般来说对于普通的文件,是每个Block一个分片;不同的输入数据类型有完全不同的分片方法。
createRecordReader() 用来提供RecordReader

对于输入的数据首先就是要分片,每一片对应着一个Mapper,Mapper数量总是等于分片数,所以分片确定之后,Mapper数量也就定了。
分片是在JobSubmitter中就完成的,在提交作业的时候会包含分片信息。(分片信息以文件的形式保存)

MR作业被提交到RM,RM会找一个节点建立这个作业的MRAppMaster,MRAppMaster也就获得了分片信息。

Map阶段


MRAppMaster解析分片信息,为每个分片创建一个MapTask,并且尽量投放到最佳目的地上执行(一般是数据所在的节点)。
创建MapTask的时候也就创建了Partitioner,用来确定每一条Map的结果数据分配给哪个Reducer。

MapTask中利用RecorderReader迭代读取此分片中的记录,对每一条记录调用用户自定义的Map函数来处理。
Map的输出是KV对。

关于Map的数据写出

Map写出的数据最终通过MapOutputBuffer类来收集。而实际上数据在到达MapOutputBuffer之前已经又多了一个partition的数据。

MapOutputBuffer将数据连同元数据首先被写入一个100M(可自定义)的环形缓冲区,数据条目经过序列化是不定长的,而元数据是定长的。
数据和元数据从同一个起点开始,分别向两个方向延伸生长。
元数据包括:V值的起点下标,K值的起点下标,Partition和V值的长度。

当缓冲区被占用超过80%(可自定义)的时候,会触发一次spill(由一个单独的线程完成),将数据刷到本地硬盘上,而在这个过程中map产生的数据可以继续写入缓冲区。
spill完成后,被刷出的数据所占用的缓冲区就释放了。
此时,数据与元数据的起点就不一样了(因为中间除掉了80%),需要将这部分元数据搬到与数据起点相同的位置。

关于Spill

spill首先做的是sort,按照partition+key联合排序。排序是原地排序(快速排序),数据的位置不动,元数据的位置会变成按照partition和实际数据有序的。
排序之后,对于每一个partition逐次写出到spill文件(同一个文件)。
如果有combiner会对这个分区做一次Reducer,如果没有就直接逐条写出。
写出的内容不包含Partition,文件按partition分割的信息需要在索引文件中记录(可以不去管)

一个MapTask的结束

等到处理完分片内的所有数据记录,会最后再做一次spill,完成之后做一次MergeParts,合并这个MapTask产生的所有Spill文件。
合并Spill文件的时候,如果Spill文件数大于一定数值还会再一次combine。
最终合并后的文件都是按照partition分区分段的。分区信息应该在索引文件中。
MapTask结束前会把输出文件的信息上传,上传给MRAppMaster(JobImpl),然后任务就结束了。

Reduce阶段


ReduceTask会在MapTask运行到差不多的时候启动。一个ReduceTask就是用来处理所有MapTask产出的某个Partition的数据。
ReduceTask大体分两个阶段:shuffle阶段和reduce阶段。

shuffle

shuffle阶段可以提前开始,但是一定要等到最后一个MapTask完成之后才能完成。因为shuffle要把所有数据合并到一起并排序。
所以如果有一个MapTask特别慢,会导致shuffle无法完成,也就无法开始Reduce。

shuffle里面有一个EventFetcher线程和一组Fetcher线程,默认是5个。还有一个scheduler(ShuffleScheduler)和一个merger(MergeManager)。
EventFetcher用来从MRAppMaster获取MapTask的相关事件,如果是MapTask完成事件,则获知其产出的URI。并将这些信息告知scheduler。

Fetcher线程会等待EventFetcher的通知,获知某个MapTask完成就去索要数据。
但是Fetcher一次索要的并不是一个MapTask的数据,而是一个主机上所有MapTask的数据,因为一个主机上可能已经完成了很多MapTask。
Fetcher每完成一个MapTask数据的复制,都会告知scheduler。
MapTask所在的节点通过Netty(http服务器)提供数据传输服务。

数据拷贝过来之后会交给merger进行合并。
一个merger包含两个线程,一个InMemoryMerger一个OnDiskMerger。
merger会监控自己的队列中待合并的文件列表,在做合并排序之后,还可以再进行一次combine。
merge最终的结果是把所有的这个Reducer的输入合并到了一起。而且是有序的。

reduce

对于shuffle的结果执行实际的reduce操作。

阅读全文
0 0
原创粉丝点击