这是我参与「第四届青训营 」笔记创作活动的第3天
本节课程目录:
- Shuffle概述
- Shuffle算子
- Shuffle过程
- Push Shuffle
1.Shuffle概述
1.1 为什么Shuffle对性能如此重要?
大数据场景中,数据Shuffle表示了不同分区数据交换的过程,不同的Shuffle策略性能差异巨大。
目前在各个引擎中shuffle都是优化的重点,在Spark框架中,Shuffle是支撑Spark进行大规模复杂数据处理的基石
2.Shuffle算子
2.1 Shuffle算子分类
repartition:重新改变分区
ByKey:根据key区分聚合数据
Join:把本身没有在一起的数据根据某种规则聚合在一起进行计算
Distinct:特殊的ByKey操作
2.2 Spark对Shuffle的抽象-宽依赖和窄依赖
宽依赖将执行过程分为不同的stage,只有宽依赖存在shuffle
宽依赖对应的对象为ShuffleDependency,通过执行不同的shuffle算子创建对应的RDD来创建ShuffleDependency对象
- K-V pair RDD
- 给定K得到对应的分区
- 序列化和反序列化
- key是否需要排序的flag
optional Aggregator- shuffle过程是否有mapSideCombine的flag
2.Partitioner
HashPartitioner:根据key的HashCode对总的分区进行取模得到一个非负的值
5.Aggregator把一部分reduce的工作在map上进行,以wordcount为例,我们可以将所有分好的词全部发送给reducer去进行数数,或者在maper中将处理好的数据变成k-v形式到reducer中进行sum操作,后者相较前者更快。
3.Shuffle过程实现
具体实现:将key通过Hash写入到不同的文件中,每个文件设置一个缓冲,当缓冲区满的时候写入磁盘,避免频繁IO操作,每个磁盘文件都由下游的一个task任务进行读取。
- 写数据
1.Hash Shuffle(数据量过大时需要大量的文件资源)
2.Hash Shuffle-写数据优化(一个CPU对应一个文件对应一个task)
3.Sort Shuffle
所有文件对应一个Buffer,当内存满的时候,通过排序将相同的partition数据放在一起, 最后每个task生成一个包含所有paitition数据的文件以及一个该task数据在文件位置的偏移量。
- 读数据
- Shuffle过程的触发流程
从下往上进行创建,collect开始触发计算,task scheduler -> submit job -> 创建shuffle Rdd对象 -> 向Shuffle manager注册自己 -> 创建Map和Reduce两个stage -> 提交到executor开始计算
- 不同的ShuffleHandle对应的Writer
- BypassMergeSortShuffleWriter
- BypassMergeShuffleWriter
- UnsafeShuffleWriter
用到了堆外内存,性能更佳,但是发生内存泄漏难以排查
- SortShuffleWriter
- BypassMergeSortShuffleWriter
- 读写优化技术-zero Copy
通过sendfile系统调用实现
- Shuffle优化
- 避免Shuffle(将小的RDD进行广播)
- 使用可以map_side预聚合的算子
比如在wordcount中maper中提前算出单词出现的次数,而不需要reducer中去进行计算
- Shuffle参数优化
- Shuffle并发度过高可能产生随机读,过低可能产生作业执行太慢的问题
- 文件空不生成partition
- 在数据读取的时候进行合并,如让一个task处理10个数据
- 设置处理的最大partition的数据量
- 动态调整reduce阶段partition的数量
- 数据量过大设置数据读取速度让数据处理的速度降下来
- Shuffle倾斜优化
- 提高并行度,让数据尽可能的不要分在一起
- AQE Skew Join,根据统计信息让数据量大的数据进行切分分别进行Join计算
- 避免Shuffle(将小的RDD进行广播)
4. Push Shuffle
4.1 为什么需要Push Shuffle
4.2 Magnet实现原理
4.3 Magnet可靠性
4.4 Cloud Shuffle Service
4.5 Cloud Shuffle Service架构
4.6 Cloud Shuffle Service写入流程