目录
2. 在map阶段,框架可以执行Combiner操作【可选】
3.2 环形缓冲区的溢写,会产生多个溢写文件,按照对应分区的数据进行归并排序。将排序后的数据存储到磁盘上(比如:0,1号分区的文件)
4. Mapreduce 的 map 数量 和 reduce 数量是由什么决定的 ,怎么配置
1. MapReduce的shuffle机制(必背)
MapReduce是一种分布式计算模式,由两个阶段组成:Map和Reduce
Shuffle横跨map阶段和reduce阶段,是把数据从map端拷贝到reduce端的一个过程。
具体过程:
1. MR首先对数据进行分片,一个split产生一个mapTask任务,
2. MapTask会调用map函数把数据处理成<K, V>格式作为输出
3. MapTask的输出会先写入到内存缓冲区(100M),当内存缓冲区的大小达到80%的大小,会把内存中的数据溢写到磁盘里面(溢写之前会进行分区排序,按照key进行升序排列),一直等到MapTask把所有的数据都计算完,最后会把内存缓冲区里面剩余的数据一次性全部刷新到本地磁盘文件中。
4. 每个文件都是有多个分区的,同一个分区的数据放到一起。
5. 把所有的临时文件合并成一个大文件,因为一个map任务只会生成一个文件(也有多个分区),每个分区的数据会被shuffle线程拷贝到不同的reduce节点上。不同map任务相同分区的数据会被分到都同一个reduce节点进行合并,合并之后就会执行Reduce的功能,最终产生我们最终的结果数据。
2. 在map阶段,框架可以执行Combiner操作【可选】
可以在map阶段执行reduce逻辑,进行局部规约。
注意:并不是所有的场景适合使用规约,比如求平均值的场景。
3. shuffle衍生出来的几个问题
3.1 环形缓冲区溢写之前要进行排序?
(1)排序的手段:快排
(2)对谁排序: key的索引
(3)按照什么顺序排序:字典顺序
3.2 环形缓冲区的溢写,会产生多个溢写文件,按照对应分区的数据进行归并排序。将排序后的数据存储到磁盘上(比如:0,1号分区的文件)
3.3 Reduce阶段:
reduceTask去各个MapTask上拷贝同一分区的数据(只拷贝一个分区的)。数据放到内存->磁盘,然后进行归并、分组,进入reduce
3.4 哪些地方能够压缩?
map输入端、map输出端、reduce输出端
(1)map输入端的数据考虑什么?数据量超过128M需要考虑切片,切片:lzo/bzip2
(2)map输出端考虑什么呢? 要考虑速度快, snappy/lzo/bzip2
(3)reduce输出端要考虑什么呢?要看数据最终流向。永久保存、切片(进入一下MR)
3.5 shuffle优化
1)设置环形缓冲区大小为200兆,溢写比率设置为90-95%(可以减少溢文件的个数)
2)对溢写文件combine
3)对溢写文件进行归并,默认一次10个,可以改为20个(服务性能ok)
4)压缩优化:压缩snappy/lzo
5)增大reduce阶段拉取的个数:假如有100maptask,reduce默认一次拉取5个maptask分区的数据,Reduce性能Ok可以设置10~15,增加内存。
4. Mapreduce 的 map 数量 和 reduce 数量是由什么决定的 ,怎么配置
- map数量是由任务提交时,传来的切片信息决定的,切片有多少,map数量就有多少
- reduce的数量是可以自己设置
5. Partition分区类别与规则
- Partition分区:按照一定的分区规则,将key value的list进行分区。
- 分区的创建分为默认的和自定义两种。
- 默认分区是根据key的hashCode对ReduceTasks个数取模得到的。
- 用户没法控制哪个key存储到哪个分区。
public class HashPartitioner<K,V> extends Partitioner<K,V>{
public int getPartition(K key,V value, int numReduceTasks){
return(key.hashCode()& Integer.MAX_VALUE) % numReduceTasks;
}
}
- 自定义类继承Partitioner,重写getPartition()方法
public class xxx extends Partitioner<Text, xxx>{
@Override
public int getPartition(Text key,xxx value, int numReduceTasks){
// 控制分区代码逻辑
...
...
...
return Partition;
}
}
- 设置自定义Partitioner:
job.setPartitionerClass(CustomPartitioner.class);
- 根据自定义Partitioner的逻辑来设置ReduceTask的数量:
job.setNumReduceTasks(n);