如 map 端的细节图,Shuffle 在 reduce 端的过程也能用图上标明的三点来概括。当前 reduce copy 数
据的前提是它要从 JobTracker 获得有哪些 map task 已执行结束,这段过程不表,有兴趣的朋友可以关注
下。Reducer 真正运行之前,所有的时间都是在拉取数据,做 merge,且不断重复地在做。如前面的方式
一样,下面我也分段地描述 reduce 端的 Shuffle 细节:
1. Copy 过程,简单地拉取数据。Reduce 进程启动一些数据 copy 线程(Fetcher),通过 HTTP(jetty)
方式请求 map task 所在的 TaskTracker 获取 map task 的输出文件。因为 map task 早已结束,这些文件就归
TaskTracker 管理在本地磁盘中。
2. Merge 阶段。这里的 merge 如 map 端的 merge 动作,只是数组中存放的是不同 map 端 copy 来的数
值。Copy 过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比 map 端的更为灵活,它基于 JVM
的 heap size 设置,因为 Shuffle 阶段 Reducer 不运行,所以应该把绝大部分的内存都给 Shuffle 用。这里需
要强调的是,merge 有三种形式:1)内存到内存 2)内存到磁盘 3)磁盘到磁盘。默认情况下第一种形式不
启用,让人比较困惑,当内存中的数据量到达一定阈值,就启动内存到磁盘的 merge。与 map 端类似,
这也是溢写的过程,这个过程中如果你设置有 Combiner,也是会启用的,然后在磁盘中生成了众多的溢
写文件。第二种 merge 方式一直在运行,直到没有 map 端的数据时才结束,然后启动第三种磁盘到磁盘
的 merge 方式生成最终的那个文件。
3. Reducer 的输入文件。不断地 merge 后,最后会生成一个“最终文件”。为什么加引号?因为这个文
件可能存在于磁盘上,也可能存在于内存中。对我们来说,当然希望它存放于内存中,直接作为 Reducer
的输入,但默认情况下,这个文件是存放于磁盘中的。至于怎样才能让这个文件出现在内存中,后面有
时间我再说。当 Reducer 的输入文件已定,整个 Shuffle 才最终结束。然后就是 Reducer 执行,把结果放
到 HDFS 上。