上一篇讲了BypassMergeSortShuffleWriter实现形式,并且晓得抉择BypassMergeSortShuffleWriter的时候,分区数是不能超过200的,因为每次执行的时候,会依据分区数量,学生成临时文件,如果分区数很多的话,那就会很有很多的临时文件,磁盘性能就十分不好。
UnsafeShuffleWriter也是不具备聚合性能的,然而他应用Tungsten的内存作为缓存,这样磁盘的性能就失去了大大的晋升。

流程

拿到RDD的后果后,迭代每条记录,把记录的键值对写入到SerializationStream的输入流中,SerializationStream是包装了名为serBuffer的MyByteArrayOutputStream对象。

而后把字节数组交给ShuffleExternalSorter,一个专门用于对Shuffle数据进行排序的内部排序器。内部排序器拿到字节数组,发现此时没有page(即MemoryBlock),于是就创立了一个page,把字节数组放在page中。另外须要把创立的page退出到曾经调配的Page列表allocatedPages,并把创立的page作为currentPage。

同时还要记录元数据信息,寄存在ShuffleInMemorySorter的长整型数组中用于排序,其中高24位存储分区ID,两头13位存储页号,低27位存储偏移量。

反复着下面的步骤,迭代RDD每条记录,直至page没有足够的空间。

此时就要申请调配新的Page,把这个page退出到曾经调配的Page列表allocatedPages,并把新创建的page作为currentPage,新的字节数组就往新的page里放。

RDD的后果持续迭代,ShuffleInMemorySorter中的记录数超过设定的值,或者长整型数组曾经不够用然而无奈扩大的时候,就须要内存中的数据将被溢出到磁盘。
首先是对内存中的数据依据分区进行排序,咱们上面用0或1示意分区,XY标识页号和偏移量。通过排序后,内存中的数据就依据分区有序的排列起来。

而后依据分区,把数据写入文件中,并把文件信息写在SpillInfo中,SpillInfo记录了这个文件的信息、blockId信息以及每个分区对应文件里的长度(比方4,4)。这个SpillInfo最终寄存在元数据信息的列表spills中。

数据都保留在磁盘后,那内存中的数据就能够革除回收了,包含曾经调配的Page列表allocatedPages、每个page、currentPage、ShuffleInMemorySorter。

假如RDD的后果在写完3次file时完结了,那此时spills列表就有3个SpillInfo,每个SpillInfo都指向着文件,并且记录每个分区对应的长度(假如为(4,4),(3,2),(5,1))。

最终依据spilss列表中的3个SpillInfo,依据每个分区对应的长度,把每个文件分区0的内容写入到新的文件,并记录分区0的长度为12,再把每个文件分区1的内容写入到新的文件,并记录分区1的长度为7,依据两个分区的长度,生成索引文件。

和BypassMergeSortShuffleWriter比起来,假如有1万个分区,BypassMergeSortShuffleWriter是会学生成1万个临时文件,最初再进行合并,而UnsafeShuffleWriter是依据RDD后果集的数据大小,生成临时文件,大大减少了临时文件的个数。