Map端的Shuffle:
1.map方法在处理完成数据之后会将结果写出到MapTask自带的缓冲区,每一个MapTask自带一个缓冲区。
2.数据在缓冲区中进行分区,排序,如果指定了Combiner,那么数据在缓冲区中还会进行合并combine(在缓冲区中的排序是将完全无序的数据进行排序,是快速排序)。
3.缓冲区是维系在内存中的,默认是100M。
4.当缓冲区的使用达到一定限度(溢写阈值0.8)的时候,会将缓冲区的数据溢写(spill)到磁盘上,map方法后续产生的结果会继续写到缓冲区中。
5.每一次溢写都会产生一个新的溢写文件-单个溢写文件中的数据是分区且有序的,所有的溢写文件之间是局部有序的。
6.在map方法完成之后,将所有的溢写文件进行合并(merge),将所有的溢写文件合并成一个结果文件(final out),在merge合并过程中,数据会再次进行分区排序,final out是整体分区且有序的,merge过程中的排序是将局部有序变成整体有序,所以采用的是归并排序。
7.如果map方法执行完成之后,缓冲区依然有数据,则会直接合并到最后的final out中。
8.如果指定了combiner,在merge过程中,如果spill文件大于等于3个,则在merge的时候的时候再进行一次combine。
9.注意问题:
a.spill过程不一定产生。
b.默认情况下,溢写文件的大小就是80M,考虑序列化因素。
c.缓冲区本质上是一个环形的字节数组,设置为环形的目的是为了避免寻址,能够重复利用缓冲区。
d.阈值的作用是减少写入的阻塞。
Reduce端的Shuffle
1.ReduceTask启动多个fetch线程去mapTask抓取对应分区的数据。
2.ReduceTask将从每一个mapTask抓取过来的数据存储在一个本地文件中。
3.将抓取进来的数据进行一次merge,合并成一个大文件,在merge过程,会再次进行排序就,采用的是归并排序。
4.merge完成之后,reduceTask会将相同的键对应的值放到一个迭代器中,这个过程称之为分组(group)。
5.分组完成之后,每一个键对应一个迭代器,每一个键会调用该一次reduce方法。
6.注意问题
a.ReduceTask的启动阈值:0.05,当有5%的MapTask结束,就会启动ReduceTask去抓取数据。
b.fetch线程通过HTTP请求获取数据。
c.fetch线程的数量默认为5。
d.merge因子:10,每10个小文件合并成一个大文件(如果文件数量>merge因子,那么合成最后一个之前的文件数量要和merge因子相等)。
Shuffle的调优
1.减少溢写次数
a.增大缓冲区,实际过程中,缓冲区的大小一般在250到400之间。
b.增大缓冲区阈值,同时增加了写入阻塞的风险—不建议。
c.增加combine的过程。
2.可以考虑将Map的结果文件进行压缩,这个方案是在网络资源和CPU资源之间的取舍。
3.增加fetch线程的数量。
4.增大merge因子,会增加底层计算的复杂度。不建议使用。
5.减少ReduceTask的启动阈值,增加了ReduceTask的阻塞风险。不建议使用 (文件比较大,切片比较多的时候适用)。