这是我参与「第四届青训营 」笔记创作活动的的第6天
- Shuffle概述
- MapReduce
- Map
- 在单机上对一小块数据进行计算的过程
- Shuffle
- 在map的基础上,进行数据移动,为后续的reduce阶段做准备
- Reduce
- 对移动后的数据进行处理,依然是在单机上处理一小份数据
- Map
- Shuffle对性能的影响
- MxR次网络连接
- 大量的数据移动
- 数据丢失风险
- 可能存在大量的排序操作
- 大量的数据序列化、反序列化操作
- 数据压缩
- 总结
- 在大数据场景下,数据Shuffle表示了不同分区数据交换的过程,不同的Shuffle策略性能差异较大,目前在各个引擎中Shuffle都是优化的重点,在Spark框架中,Shuffle是支持Spark进行大规模复杂数据处理的基石
- MapReduce
- Shuffle算子
- Spark中会产生Shuffle的算子大概可以分为4类
- Repartition
- coalesce
- repartition
- ByKey
- groupByKey
- reduceByKey
- aggregateByKey
- combineByKey
- sortByKey
- sortBy
- Join
- cogroup
- join
- leftOuterJoin
- intersection
- subtract
- subtractByKey
- Distinct
- distinct
- 当出现一个宽依赖时,Spark将其划分为两个stage,两个stage间会产生Shuffle操作
- Repartition
- Shuffle Dependency构造
- Partitioner
- 负责将key映射成一个数字,这个数字就代表一个分区
- HashPartitioner
- Aggregator
- 提前做一部分reduce
- Partitioner
- Spark中会产生Shuffle的算子大概可以分为4类
- Shuffle过程
- Hash Shuffle
- 写数据
- 每个partition会映射到一个独立的文件
- 写数据优化
- 每个partition会映射到一个文件片段
- 写数据
- Sort Shuffle
- 写数据
- 每个task生成一个包含所有partition数据的文件
- 写数据
- 读数据
- 每个reduce task分别获取所有map task生成的属于自己的片段
- Shuffle过程的触发流程
- Collect Action->SubmitJob->GetDependencies->RegisterShuffle
- Shuffle Handle的创建
- Register Shuffle做的最重要的事情是根据不同条件创建不同的Shuffle Handle
- Writer实现
- BypassMergeShuffleWriter
- 不需要排序,节省时间
- 写操作的时候会打开大量文件
- 类似Hash Shuffle
- UnsafeShuffleWriter
- 使用类似内存页储存序列化数据
- 数据写入后不再反序列化
- SortShuffleWriter
- 支持combine
- 需要combine时,使用PartitionedAppendOnlyMap,本质是个HashTable
- 不需要combine时,使用partitionedPairBuffer,本质是个array
- BypassMergeShuffleWriter
- Reader实现
- 网络时序图
- 使用基于netty的网络通信框架
- 位置信息记录在MapOutputTracker中
- 主要会发送两种类型的请求
- OpenBlocks请求
- Chunk请求或者Stream请求
- ShuffleBlockFetchIterator
- 区分local和remote节省网络消耗
- 防止OOM
- maxBytesFlight
- maxReqsInFlight
- maxBlocksInFlightPerAddress
- maxReqSizeShuffleToMem
- maxAttemptsOnNettyOOM
- Externel Shuffle Service
- ESS作为一个存在于每个节点上的agent为所有Shuffle Reader提供服务,从而优化了Spark作业的资源利用率,MapTask在运行结束后可以正常退出
- 优化
- Zero Copy
- DMA(Direct Memory Access)
- 直接存储器存取,是指外部设备不通过CPU而直接与系统内存交换数据的接口技术
- sendfile
- sendfile+DMA gather copy
- 可以用于合并文件以及发送文件时
- DMA(Direct Memory Access)
- Netty Zero Copy
- 可堆外内存,避免JVM堆内存到堆外内存的数据拷贝
- CompositeByteBuf、Unpooled.wrappedBuffer、ByteBuf.slice,可以合并、包装、切分数组,避免发生内存拷贝
- Netty使用FileRegion实现文件传输,FileRegion底层封装了FileChannel#transferTo()方法,可以将文件缓冲区的数据直接传输到目标Channel,避免内核缓冲区和用户缓冲区之间的数据拷贝
- 避免Shuffle
- 使用broadcast代替join
- 使用可以map-side预聚合的算子
- 参数优化
- Shuffle倾斜优化
- 倾斜影响
- 作业运行时间变长
- Task OOM导致作业失败
- 提高并行度
- 优点:足够简单
- 缺点:只缓解、不根治
- Spark AQE Skew Join
- AQE根据Shuffle文件统计数据自动检测倾斜数据,将那些倾斜的分区打散成小的子分区,然后各自进行join
- 倾斜影响
- Zero Copy
- 网络时序图
- 常见问题
- 数据存储在本地磁盘,没有备份
- IO并发:大量RPC请求(MxR)
- IO吞吐:随机读、写放大(3X)
- GC频繁,影响NodeManager- Push Shuffle
- Hash Shuffle
- Magnet
- Spark driver组件,协调整体的Shuffle操作
- map任务的Shuffle write过程完成后,增加了一个额外的操作push-merge,将数据复制一份推到远程Shuffle服务上
- magnet shuffle service是一个强化版的ESS,将隶属于同一个Shuffle partition的block,会在远程传输到magnet后被merge到一个文件中
- reduce任务从magnet shuffle service接收合并好的Shuffle数据
- 实现细节
- bitmap
- 存储已merge的mapper id,防止重复merge
- position offset
- 如果本次block没有正常merge,可以恢复到上一个block的位置
- currentMapId
- 标识当前正在append的block,保证不同mapper的block能依次append
- bitmap
- 本质上,维护了两份的Shuffle数据的副本
- Cloud Shuffle Service
- IO聚合
- 所有mapper的同一个partition数据都远程写道同一个文件(或者多个文件)
- 备份
- HDFS太重,使用双磁盘副本
- 写入速度
- 主从InMemory副本,异步刷盘,极小的失败几率去换取高速写入速度
- IO聚合