shuffle中的Collect过程怎么理解?
答:Collect过程是这样的:每个 Map 任务不断地以对的形式把数据输出到在内存中构造的一个环形数据结构中。使用环形数据结构是为了更有效地使用内存空间, 在内存中放置尽可能多的数据。
这个数据结构其实就是个字节数组, 叫 Kvbuffer, 名如其义, 但是这里面不光放置了数据, 还放置了一些索引数据, 给放置索引数据的区域起了一个 Kvmeta 的别名, 在 Kvbuffer的一块区域上穿了一个 IntBuffer(字节序采用的是平台自身的字节序) 的马甲。 数据区域和索引数据区域在 Kvbuffer 中是相邻不重叠的两个区域, 用一个分界点来划分两者,分界点不是亘古不变的,而是每次Spill之后都会更新一次。初始的分界点是 0,数据的存储方向是向上增长,索引数据的存储方向是向下增长,如图所示:

Kvbuffer的存放指针bufindex是一直闷着头地向上增长,比如 bufindex 初始值为 0,一个 Int 型的 key 写完之后, bufindex 增长为 4, 一个 Int 型的 value 写完之后, bufindex增长为 8。
索引是对在 kvbuffer 中的索引, 是个四元组, 包括: value 的起始位置、 key 的起始位置、partition 值、value 的长度,占用四个Int长度, Kvmeta的存放指针Kvindex 每次都是向下跳四个“格子”, 然后再向上一个格子一个格子地填充四元组的数据。 比如 Kvindex 初始位置是-4, 当第一个写完之后, (Kvindex+0)的位置存放 value 的起始位置、 (Kvindex+1)的位置存放 key 的起始位置、 (Kvindex+2)的位置存放 partition 的值、 (Kvindex+3)的位置存放value 的长度, 然后 Kvindex 跳到-8 位置, 等第二个和索引写完之后, Kvindex 跳到-32 位置。
Kvbuffer 的大小虽然可以通过参数设置, 但是总共就那么大, 和索引不断地增加, 加着加着, Kvbuffer 总有不够用的那天, 那怎么办? 把数据从内存刷到磁盘上再接着往内存写数据, 把 Kvbuffer 中的数据刷到磁盘上的过程就叫 Spill, 多么明了的叫法, 内存中的数据满了就自动地 spill 到具有更大空间的磁盘。
关于 Spill 触发的条件, 也就是 Kvbuffer 用到什么程度开始 Spill, 还是要讲究一下的。如果把 Kvbuffer 用得死死得, 一点缝都不剩的时候再开始 Spill, 那 Map 任务就需要等 Spill完成腾出空间之后才能继续写数据; 如果 Kvbuffer 只是满到一定程度, 比如 80%的时候就开始 Spill, 那在 Spill 的同时, Map 任务还能继续写数据, 如果 Spill 够快, Map 可能都不需要为空闲空间而发愁。 两利相衡取其大, 一般选择后者。
Spill 这个重要的过程是由 Spill 线程承担, Spill 线程从 Map 任务接到“命令”之后就开始正式干活, 干的活叫 SortAndSpill, 原来不仅仅是 Spill, 在 Spill 之前还有个颇具争议性的Sort。








暂无数据