这是我参与「第四届青训营 」笔记创作活动的的第8天
1. 概述
-
MapReduce(MR)
-
Shuffle 阶段:在map阶段基础上进行数据移动
-
reduce阶段:数据处理
-
为什么shuffle对性能重要:M * R次网络连接;大量的数据移动;数据丢失风险;大量的排序操作;大量的序列化反序列化操作;数据压缩
2. 算子
- 算子分类
(1)repartition:重新分区
(2)byKey:聚合
(3)join:本身不在一起的数据放在一起
(4)distinct:特殊的bykey
-
Spark中对shuffle的抽象——宽依赖,窄依赖
-
内部依赖关系(ShuffleDependency)
- Cogroup
- ShuffledRDD
(1)Partitioner:
两个接口:numberPartitions;getPartition
(2) Aggregator
creatCombiner:只要一个value的时候的初始化
mergeValue:合并一个value到Aggregator
mergeCombiners:合并两个Aggregator
3. 过程
- Hash Shuffle
-
每个partition会映射到一个独立的文件M * R
-
每个partition会映射到一个文件片段
- Sort shuffle
- 每个task生成一个包含所有partition数据的文件,相同内容排序
- 读数据
- 每个reduce task分别获取所有map task生成的属于自己的片段
- 过程的触发流程
graph TD
CollectAction --> SubmitJob --> GetDependencies --> RegisterShuffle
-
Shuffle Handle 的创建
-
BypassMergeShuffleWriter
- 不需要排序
- 写操作时会打开大量文件
- 类似于HashShuffle
- UnsafeShuffleWriter
- 不再反序列化
- 使用类似内存页储存序列化数据
- 只根据partition排序Long Array
- 数据不移动
- SortShuffleWriter
- 支持combine
- 需要combine时,本质是HashTable
- 不需要时,本质是array
- Reader实现
(1)Iterator
(2)External Shuffle Service: 区分local和remote节省网络消耗;防止OOM
- Zero copy
Netty Zero Copy:可堆外内存
DMA:直接存储器存取
- 问题
- 没有备份
- IO并发:大量RPC请求
- IO吞吐:随机读
- GC频繁
- Shuffle 优化
-
避免shuffle:使用broadcast代替join
-
使用map-side预聚合算子
- Shuffle 倾斜优化
- 作业运行时间边长
- Task OOM导致作业失败
- 处理:提高并行度(足够简单;只缓解)
- Spark AQE Skew Join
将倾斜分区打散成小的子分区
4. Push Shuffle
- 为什么需要?
- Avg IO size太小,造成了大量的随机IO
- M*R次读请求,大量的网络连接
-
实现
-
Magnet实现原理
- bitmap:储存已merge的mapper id
- position offset:可恢复到上一个block位置
- currentMapId
-
Magnet可靠性
-
Cloud Shuffle Service