包括Mapper(Mapper类)阶段和Reducer(Reducer类)阶段,其中Map阶段和Reduce阶段都包含部分Shuffle阶段工作。
Map阶段
block块切分成多个分片,每个输入分片会让一个map进程来处理
任务: i. 初始化: 创建context,map.class实例,设置输入输出,创建mapper的上下文
任务把分片传递给 TaskTracker 里面的 InputFormat类的 createRecordReader() 方法以便获取分片的 RecordReader 对象,由RecordReader读取分片数据并转成键值对形式。
:run()方法,这个方法可以被重写,对每个分片里的数据执行一样的方key生成一个value=1)
(Map端):
:map会使用Mapper.Context.write()将map函数的输出溢写到内存中的环形缓冲区,同时调用reducer。当缓冲区即将充满(80%),溢写会被执map会停止写入内存)
具体过程 a.创建一个溢写记录SpillRecord 和一个FSOutputStream 文件输出流(本地文件系统)
内存内排序缓冲中的块:输出的数据会使用快排算法按照partitionIdx, key排序
combiner(可选),方便排序
合并溢写文件,如果合并后文件较大,可以再进行一次combiner
再进行一次Partitioner对数据分区 (为什么要两次呢,因为这个时候可能进行了两次,应该分配到每个reducer上的数据出现变化)
合并阶段(可选,有两次触发时机):简单地合并key值
减少传到reducer的数据量(即通过减少key-value对减少网络传输)
减轻reducer的负担
缺点 job没有依赖,有磁盘io开销
(补充):
默认的Partitioner是Hash Partitioner,对key计算hash值并分区
按照数据大小分区 常用于全局排序 按照大小将数据分成多个区间,后一个区间的数据一定大于前一个区间
可以被重写,克服低效分区,解决数据倾斜和全局排序问题
排序原因:
方便reducer找到自己分区的数据
减轻reducer中排序负担
Reduce阶段
(Reduce端):
端并行的从多个map下载该reduce对应的partition部分数据(通过HTTP)
: Reduce将map结果下载到本地时,需要把多个mapper输入流合并成一个,一map下载数据完毕。
对下载下来的map数据,会先缓存在内存中,当内存达到一定用量时写入硬盘(这里也可以进行combiner)
map数据下载过程中,一个后台线程把这些文件合并为更大的,有序的文 件,也就是进行全局排序,为最后的最终合并减少工作量(多轮)
merge(方式不确定): map数据下载完毕后,所有数据被合并成一个整体有序的文件作为 Reduce的输入。有可能是都来自于硬盘,有可能都来自于内存,也有可能两边都有
任务:
map方法类似 通常做聚合操作
() 方法把 reduce 任务的输出结果写到 HDFS