MapReduce之Shuffle详解
Hadoop原生的计算框架MapReduce,简单概括一下:进程量级很重,启动很慢,但能承载的数据量很大,效率相较于Spark微批处理和Flink实时来讲很慢,Shuffle任何一个写MR同学都必须掌握的东西,说难不难,说简单也不简单
MapReduce程序的五个阶段:
- input
- map
- shuffle
- reduce
- output
我将Shuffle阶段加粗了,原因很简单,因为这里很重要
1. 关于Shuffle过程实现的功能:
1. 分区:
- 决定当前的Key交给哪个Reducer进行处理,相同的Key则由相同的Reducer处理
- 默认是根据Key的Hash值,对Reduce个数取余(源码如下)
public int getPartition(K2 key, V2 value, int numReduceTasks) { return (key.hashCode() & Integer.MAX_VALUE) % numReducTasks }
2. 分组
- 将相同的Key的value进行合并
- Key相等时将分到同一个组里面
- MapReduce阶段,一行调用一次Map方法,一种Key调用一次Reduce
3. 排序:将Key按照字典排序
2. 关于Shuffle过程实现功能的详细描述:
1. Map端Shuffle:
-
Spill:溢写
-
每一个Map处理之后的结果都会进入环形缓冲区(内存,默认100M)(关于环形缓冲区有必要单独了解一下,不详细展开了)
-
分区:对每一条key-value进行分区,打标签
-
排序:将相同分区的数据进行分区内排序
-
当环形缓冲区达到阈值的80%,将分区排序后的数据写到磁盘变成文件,最终会生成多个小文件,
-
Merge合并:
-
将spill生成的小文件进行合并
-
将相同分区的数据进行排序
-
-
(Map task结束)通知ApplicationMaster,Reduce主动过来拉取数据Reduce端Shuffle
2. Reduce端Shuffle:
-
启动多个线程,去每台机器上拉去属于自己分区的M数据
-
Merge:
-
将每个Maptask的结果属于自己分区的数据进行合并
-
将整体属于自己分区的数据进行排序
-
-
分组:对相同的key的value进行合并
3. 关于MapReduce的Shuffle优化:
MapReduce Shuffle过程的优化:
-
Combiner:合并
-
在map阶段提前进行了一次合并,一般来说等同于提前进行了reduce,降低reduce的压力
-
不是所有的程序都适合combiner
-
Compress:压缩
-
能大大减少磁盘和网络的IO
-
hadoop中设置压缩:
-
hadoop checknative查看本地支持哪些压缩
-
常见的压缩格式:snappy,lzo,lz4
-
修改本地支持的压缩方式:替换lib/native
-
MapReduce程序可以设置压缩的位置:
-
输入
-
map的中间结果(需要同时指定)
-
mapreduce.map.output.compress
-
mapreduce.map.output.compress.codec=默认是DefaultCodec
-
reduce的输出
-
mapreduce.output.fileoutputformat.compress
-
Mapreduce,output.fileoutputformat.compress.codec
-
怎么设置压缩:
-
集群配置文件内
-
设置conf对象当前程序有效
-
运行时指定参数: -Dmapreduce.output.fileoutputformat.compress=true ….