一、Mapper的Shuffle
- MapTask在接收到FileSplit之后进行按行读取
- 每读取一行调用一次map方法
- 执行完一次map之后会将输出的数据写到缓冲区中
- 缓冲区的大小默认是100M,可以通过io.sort.mb来进行调节
- 在缓冲区中,会对数据进行分区-partition,排序 - sort,合并 - combine操作
- 当缓冲区的容量利用率达到阈值0.8的时候,会启动给一个后台线程将缓冲区中的数据写到指定目录下的溢写文件中,这个过程称之为是溢写 (Spill)
- 每次的Spill都会产生一个新的溢写文件
- 等最后所有的数据都写完之后,会将所有的溢写文件进行一次合并 (merge),合并到一个新的分区并且排序的文件中
- 如果在最终合并的时候,溢写文件个数>=3,那么合并完成之后会再执行一次Combiner
二、注意问题
- 当产生溢写的时候,缓冲区最后残留的数据会flush到最后一个溢写文件中
- Spill理论上默认是80M,但是要考虑序列化以及最后的冲刷等因素
- 不能凭借一个MapTask处理的切片大小来衡量MapTask之后的输出数据的多少
- 每一个切片对应一个MapTask,每一个MapTask对应一个缓冲区
- 缓冲区本质上是一个字节数组
- 缓冲区又叫环形缓冲区,好处在于可以重复利用同一块地址的缓冲区
- 阈值的作用是避免Spill过程产生阻塞
- merge过程可能不会发生
三、Reducer的Shuffle
- ReduceTask通过Http的方式来得到输出文件的分区,这个过程称之为fetch
- 每一个ReduceTask将获取的分区的数据再次进行merge,然后进行排序
- 将相同的key做聚合,将值放入迭代器中,这一步称之为grouping
- 调用reduce方法,将key和迭代器传入
四、注意问题
- fetch的默认线程数是5
- ReduceTask的阈值为5%,即当5%的MapTask完成之后,ReduceTask就开始启动
- Merge因子默认为10,即每10个文件合并成一个文件
五、流程图
六、Shuffle调优
- Map阶段的调优:
- 调大缓冲区,一般可以调为250~350M
- 可以引入combine过程
- merge之后的文件可以进行压缩,减少网络传输的消耗
- Reduce阶段的调优:
- 增多fetch的线程数
- 降低ReduceTask的阈值
- 提高merge因子