大数据Shuffle原理与实践||青训营
今天是我参加青训营的第五天。
一、Shuffle概述
1.1MapReduce概述
2004年谷歌发布《Mapreduce:Simplified DATa PRocessingonlarge clusters》论文
在开源实现的MapReduce中,存在Map、Shuffle、Reduce三个阶段。
1.2Map阶段
map阶段,是在单机上进行的针对一小块数据的计算过程
1.2shuffle阶段
shuffle阶段,在map阶段的基础上,进行数据移动,将相同的放在一起,为后续的reduce阶段做准备,
1.3Reduce阶段
reduce阶段,对移动后的数据进行处理,依然是在单机上处理一小份数据
1.4为什么shuffle对性能非常重要
1.M*R次网络连接
2.大量的数据移动
3.数据丢失风险
4.可能存在大量的排序操作
5.大量的数据序列化、反序列化操作
6.数据压缩
01总结
在大数据场景下,数据shuffle表示不同分区数据交换的过程,不同的shuffle策略性能差异较大
目前在各个引擎中shuffle都是优化的重点,在spark框架中shuffle是支撑spark进行大规模复杂数据处理的基石。
2.Shuffle算子
2.1shuffle算子分类
repartition BYkey join distinct
一般改变分区 聚合同类型数据 本身没有相关的数据放在一起 特殊的bykey操作
2.2Sparl中对shuffle的抽象-宽依赖、窄依赖
窄依赖:父RDD的每个分片至多被子RDD的一个分片所依赖
宽依赖:父RDD中的分片可能被子RDD中的多个分片所依赖
2.2算子内部的依赖关系
shuffleDependency
CoGroupedRdd
Cogroup
fullOuterjoin、rightOuterJoin、leftOUterjoin
join
ShuffedRDD
combineBykeywithclass Tag
combinebykey
reduceBykey
Coalesce
SortBykey
sortby
2.2.1 Shuffle Dependency构造
第二个负责给定一个key产生一个key的分区
第三个负责把一个对象映射成二进制流或相反
第四个负责排序的flag
2.2.1SHuffle dependency构造-partitioner
两个接口
numberPartitions
getPartitioner
经典实现
HashPartitioner
2.2.1SHuffle dependency构造-Aggregator
createCombiner:只有一个value的时候初始化的方法
mergevalue:合并一个value到Aggregator中
mergeCombiners:合并两个Aggregator,把两个加起来输入真正的merge
3.Shuffle实现的发展历程
3.1Hash Shuffle-写数据
每个partition会映射到一个独立的文件
3.1Hash Shuffle-写数据优化
每个partition会映射到一个文件片段,这样的话还是会m改成c文件还是不会下降多少,而且文件的打开数还没有减少多少=。
3.2Sort shuffle:写数据
每个task生成一个包含所有partition数据的文件,
3.3Shuffle-读数据
每个reduce task分别获取所有mao task生成的属于自己的片段
3.4Shuffle过程的触发流程
在第六行这个collect是一个action 在前五行只是一个计算对象,只有后面才会触发过程
3.5shuffle handle的创建
Register Shuffle时做的最重要的事情是根据不同条件创建不同的shuffle Handle
3.6Shuffle handle 与shuffle writer的对应关系
3.7Writer实现-BypassMergeShuffleWriter
不需要排序,节省时间
写操作的时候会打开大量文件
类似于Hash Shuffle
节省CPU,虽然不一样的地方,多了一个操作,最终还是会整合到一起
3.7Writer实现-UnsafeShuffleWriter
没有java内存的开销也没有垃圾回收的开销
使用类似内存存储存序列化数据
数据写入不再反序列化
3.7Writer实现-UnsafeShuffleWriter
只根据partition排序long Array
数据不移动
long array不能超过24的次方
3.7Writer实现-SortShuffleWriter
支持combine
需要combine时,使用PartiotionedAppendOnlyMap,本质三个HashTable
不需要combine时PartitionePairBuffer本质是个array
3.8Reader实现-网络时序图
使用基于netty的网络通信框架
位置信息记录在MapOutputTracker中
主要会发送两张类型的请求
OPenBlocks请求
chunk请求或Stream请求
对于没有聚合操作只会生成一个简单的迭代器。
3.7Reader实现-ShuffleBlockFetchIterator
3.8Read实现-External shuffle Service
ESS作为一个存在与每个节点上的agent为所有Shuffle Reader提供服务,从而优化了Spark作业的资源利用率,MapTask在运行结束后可以正常退出
3.9Shuffle优化使用的技术-Zero Copy
3.10常见问题
数据存储在本地磁盘,没有备份
IO并发:大量RPC请求(M*R)
IO吞吐:随机读,写放大(3x)
GC频繁,影响NodeManager
3.11Shuffle优化
避免shuffle 使用broadcast替代join 使用可以map-side预聚合的算子,可以减少数据量
3.12Shuffle参数优化
第一个是默认的并发度 可以帮我们优化shuffle的表现,过高随机读,过低一个task处理的数据量过大,作业速度慢
第二第三类似,减少不必要的Rdd
第二如果文件是空的可以减少速度
第三我们在读取数据时可以做一些合并
第四是也是读数据task处理的数据量生成一个合适的大小
3.13Shuffle 倾斜优化
什么叫shuffle倾斜
倾斜影响
作业运行时间变长
task OOM导致作业失败
3.13常见的倾斜处理办法
提高并行度
优点足够简单
缺点:只缓解、不根治
3.13Spark AQE Skew join
AQE根据shuffle文件统计数据自动检测倾斜数据,将那些倾斜度分区打散成小的子分区,然后各自进行join
3.14案例-参数优化
3.15参数调整
减少了随机读的问题,减少了shuffle读取磁盘的数据,导致CPU浪费
四、Push Shuffle
4.1为什么需要Push Shuffle?
Avg iosize太小,造成了大量的随机IO,严重影响磁盘的吞吐
M*R次读请求,造成大量的网络连接,影响稳定性
4.2Push shuffle的实现
4.3Magnet实现原理
4.4Magnet可靠性
4.5Cloud Shuffle Service 思想
io聚合,如果文件丢失的代价是特别大的
写入速度:用极小的失败概率换取极大的速度是非常值得的
4.6Cloud Shuffle Service 架构
4.6.1Cloud shuffle Service 写入流程
4.6.2Clound shuffle service读取流程
4.6.3 2Clound shuffle service AQE
一个Partition会最终对应到多个Epoch file,每个Epoch目前设置512MB,一个大的文件划分为小文件,不需要大的文件读取很多遍