Map 阶段负责数据的过滤分发,将原始数据转化为键值对;Reduce 阶段是对数据进行合并,将具有相同的 key 值的 value 进行处理后再输出新的键值对作为最终结果。为了让 Reduce 可以并行处理 Map 的结果,必须对 Map 的输出进行一定的分区排序,然后再交给对应的 Reduce。
(1)即 Map 方法之后 Reduce 方法之前的这段数据混洗的过程叫做 Shuffle 机制。
(2)Map 方法之后,数据首先进入到分区方法,把数据标记好分区,然后把数据发送到环形缓冲区;环形缓冲区默认大小 100m,环形缓冲区达到 80%时,进行溢写;溢写前对数据进行排序,对 key 的索引按字典顺序进行快速排序;溢写产生大量溢写文件,需要对溢写文件进行归并排序;最后将文件按照分区存储到磁盘,等待 Reduce 端拉取。(对溢写的文件也可以进行 Combiner 操作,前提是汇总操作,求平均值不行。)
(3)每个 Reduce 拉取 Map 端对应分区的数据。拉取数据后先存储到内存中,内存不够了,再存储到磁盘。拉取完所有数据后,采用归并排序将内存和磁盘中的数据都进行排序。 在进入 Reduce 方法前,可以对数据按照相同的 key 进行分组操作。
相关问题:
1. 为什么 shuffle?
Shuffle 是 MR 中非常重要的一个环节,它可以对 map 阶段输出的数据进行预处理,确保 reduce 阶段可以获取到所有相关的数据 。
shuffle 操作的作用主要有以下三点:
- 将 map 阶段输出的数据按照 key 进行分组,确保 reduce 可以获取对应 key 的 value。
- 在 shuffle 过程中对数据进行排序,以便后去 reduce 阶段可以更高效地处理数据。
- 将相同 key 的数据进行合并,降低后续 reduce 处理的数据量,提高程序的执行效率。
2. 为什么使用环形缓冲区?
在 shuffle 过程中,环形缓冲区起到非常重要的作用。首先,MapTask 会将输出结果先写入环形缓冲区中,待环形缓冲区中的数据达到阈值后开始向磁盘中写入,并且继续往环形缓冲区中写入数据,直到 MapTask 的运行结束。此时 ReduceTask 启动,从磁盘中读取 MapTask 所写的数据并放入内存池中,再使用归并排序进行处理。
因此,环形缓冲区的作用如下:
- 缓冲池:扮演着一个缓冲池的角色,有效平衡 Map 和 Reduce 结点之间的速度差异和负载流量。
- 提高数据读写的效率:环形缓冲区不需要频繁的内存分配和释放操作,只需要利用指针来移动读写位置。
- 降低存储空间的使用量:环形缓冲区可以通过循环复用的方式,充分地利用已经写入的空间,避免浪费存储空间。
- 支持并发读写操作:由于环形缓冲区是一个循环结构,读写指针可以同时移动,所以可以支持多个进程或者线程同时对其进行读写操作,提高并发性。
3. 环形缓冲区的读写,内存是否可以复用?
可以复用!环形缓冲区对内存进行了循环复用,它不需要频繁地进行内存分配和释放操作,而是通过读写指针来移动位置,复用已经写入的空间,以此来提高读写效率并降低存储空间的使用量。因此,环形缓冲区的设计可以充分利用内存空间,减少内碎片,实现内存的复用。
4.MapReduce Shuffle 中 Reduce 是怎么获得 Map 输出的分区文件,Map 主动推还是 Reduce 主动拉?
答:Reduce 主动拉取
5.shuffle 中涉及到哪些排序?快排和归并排序时间复杂度是多少?
答:shuffle 中涉及到快速排序和归并排序,快速排序和归并排序的时间复杂度都为 O(nlogn)