概述
ShuffleExternalSorter是专门用于sort-based shuffle的external sorter。
传入的record会被追加到data page。当所有的record都已经插入该sorter时,或者当前线程的shuffle memory已经到达阈值时,会使用ShuffleInMemorySorter来根据record的partition id将record排序。排序后的record然后会被写入一个输出文件(或者多个文件,如果我们已经spill),输出文件的格式,与最终SortShuffleSorter写入的输出文件的格式是一致的。SortShuffleSorter会将每个输出partition的record写入一个序列化的、压缩的流,可以通过一个解压缩的、反序列化的流读取。
与org.apache.spark.util.collection.ExternalSorter不同,这个sorter不会合并spill file。相反,合并操作交给了UnsafeShuffleWriter执行,UnsafeShuffleWriter会使用专门的合并方法来避免额外的序列化和反序列化。
源码分析
成员变量
ShuffleExternalSorter有以下几个比较重要的成员变量:
- allocatedPages是用来保存待排序的record的page(MemoryBlock)链表。当发生spill后,链表中page就会被释放;
- spills是将排序后的record写入磁盘文件作为spill file后,这些spill file的元数据信息。
- inMemSorter是用来根据record的partition id将record排序的ShuffleInMemorySorter。
- currentPage,page链表中用于保存待排序的record的当前page。一个page会保存多个record,record通过追加的方式添加到page。
- pageCursor,record追加到当前page时,当前page的可用空间的起始地址(或下标)。
/**
* Memory pages that hold the records being sorted. The pages in this list are freed when
* spilling, although in principle we could recycle these pages across spills (on the other hand,
* this might not be necessary if we maintained a pool of re-usable pages in the TaskMemoryManager
* itself).
*/
//用page链表保存待排序的record。当发生spill时,链表中的page会被释放,虽然原则上我们可以在整个spill期间
//循环利用这些page(另一方面,这可能是不必要的如果我们在TaskMemoryManager中保存了一个可重复使用的page pool)
private final LinkedList<MemoryBlock> allocatedPages = new LinkedList<>();
private final LinkedList<SpillInfo> spills = new LinkedList<>();
// These variables are reset after spilling:
//spill之后会重置这些变量
@Nullable private ShuffleInMemorySorter inMemSorter;
@Nullable private MemoryBlock currentPage = null;
private long pageCursor = -1;
其中,inMemsorter的初始化如下:
它会从sparkConf中获取配置信息判断是否使用RadixSort对record进行排序,默认为true。
this.inMemSorter = new ShuffleInMemorySorter(
this, initialSize, conf.getBoolean("spark.shuffle.sort.useRadixSort", true));
insertRecord方法
插入一条record到shuffle external sorter。即追加一条record到当前page。record在当前page中的存储格式为:
record length | (k, v)
同时它也会插入一条record到ShuffleInMemorySorter,在inMemorySorter中保存record的编码地址和partitionId。record在inMemorySorter的存储格式为:
partitionId | pageNumber | offset in page