Shuffle
正常意思是洗牌或弄乱.
我们对Shuffle过程的期望:
1、完整地从map task端拉取数据到reduce 端。
2、在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗。
3、减少磁盘IO对task执行的影响。
shuffle过程简单描述:
每个map task都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个map task结束后再对磁盘中这个map task产生的所有临时文件做合并,即合并-写入-合并 ”过程,生成最终的正式输出文件,然后等待reduce task来拉数据。reduce端得到信息拉取到map输出也会从缓冲区到磁盘做“合并-写入-合并 ”的过程,最后形成reduce输入由其计算输出到hdfs。
Split :
map task执行时,数据来源于HDFS的block,map task只读取split。Split与block的对应关系可能是多对一,默认是一对一。 之后说明以WordCount为例,假设map的输入数据都是像“aaa”这样的字符串。
Partitioner :
在mapper的运行后,输出是一个key/value对: key是“aaa”, value是数值1。若job有多个reduce task,当前“aaa”交由哪个reduce去执行需要Partitioner 决定。
MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reduce task处理。
为了平均reduce的处理能力, 默认对key hash后再以reduce task数量取模。
Partitioner : hash(key) % reduce_num
Map :
- 分区计算: “aaa”经过Partitioner后返回0,
- 写缓存: 然后 key/value 对以及 Partition 的结果都被写入缓冲区, key/value partition ,序列化成字节数组 再写入
- 溢写: 缓冲区大小限制的,需要及时将数据临时写入磁盘。这个从内存往磁盘写数据的过程被称为Spill,溢写。溢写是由单独线程来完成。溢写的启动门槛是 spill.percent,默认是0.8
- 排序: 溢写线程启动,锁定这80MB的内存,对其内 key 做排序。
- combine : 如果 client 设置过 Combiner ,那么现在就是使用 Combiner 的时候了,将有相同key的key/value对的value合并计算,减少溢写到磁盘的数据量。这里, Combiner 的输出是Reducer的输入, Combiner 绝不能改变最终的计算结果。
- 多次溢写 : 若 map 的输出很大,有多次这样的溢写发生,磁盘上相应的就会有多个溢写文件存在。
- Merge : 一个map有多个溢写文件时,需要最终合并为一个。
- 在 client 没有设置 Combiner 时, Merge 只是简单收集相同key的value 形成:{“aaa”, [5, 8, 2, …]}
- 在 client 设置了 Combiner 时, Merge 会对相同key的value 做 Combiner 合并计算:{“aaa”, 计算结果}
- Merge : 一个map有多个溢写文件时,需要最终合并为一个。
- 至此,map端工作结束,最终生成的文件存放在TaskTracker够得着的某个本地目录内。一个map对应一个文件。
Reduce :
reduce task不断地通过RPC从JobTracker那里获取map task是否完成的信息
- 拉取 : reduce task得到map执行完成的通知,拉取map结果文件。
- Merge : 不断做各个map文件的 merge ,Copy过来的数据会先放入内存缓冲区中
- merge三种形式:1)内存到内存 2)内存到磁盘 3)磁盘到磁盘。 默认情况下第一种形式不启用。
- 当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。即2)内存到磁盘——溢写
- 溢写 : 如果设置过 Combiner ,也启用,生成众多的溢写文件。即 2)内存到磁盘
- merge : 第二阶段完成后(再无map数据过来),对多个溢写文件做合并。即 3)磁盘到磁盘
- Reducer计算 : 计算前面 merge结果文件,默认情况下,这个文件是存放于磁盘中的,怎样让这个文件出现在内存中,需要性能优化。