大数据 Shuffle 原理与实践|青训营笔记

139 阅读7分钟

这是我参与「第四届青训营」笔记创作活动的第 7 天。


一、笔记内容

1. shuffle概述

2. shuffle算子

3. shuffle过程

4. Push Shuffle

二、shuffle概述

1.Mapreduce

image.png

1. map阶段:在单机上进行的针对一小块数据的计算过程,如对混乱的数据排序。

2. shuffle阶段:在map阶段基础上,进行数据移动,为后续的reduce阶段做准备。

3. reduce阶段:对移动后的数据进行处理,依然是在单机上处理一小份数据。

2.为什么shuffle 对性能非常重要

1. M*R次网络连接;

2. 大量的数据移动;

3. 数据丢失风险;

4. 可能存在大量的排序操作;

5. 大量的数据序列化、反序列化操作;

6. 数据压缩。

3.批式计算的发展与shuffle

graph TD
Mapreduce --> Spark --> Spark3.2

数据shuffle表示了不同分区数据交换的过程,不同的shuffle策略性能差异较大。目前在各个引擎中shuffle都是优化的重点,在spark框架中,shuffle是支撑spark进行大规模复杂数据处理的基石。

三、shuffle算子

1.shuffle的算子分类

Spark中会产生shuffle的算子大概可以分为4类:

repartitionByKeyjoinDistinct
coalescegroupByKeycogroupdistinct
repartitionreduceByKeyjoin 
 aggregateByKeyleftOuterJoin 
 combineByKeyintersection 
 sortByKeysubtract 
 sortBysubtractByKey 

2.Spark中对shuffle的抽象

  • 窄依赖:父RDD的每个分片至多被子RDD中的一个分片所依赖;

  • 宽依赖:父RDD中的分片可能被子RDD中的多个分片所依赖。

算子内部的依赖关系

graph TD
ShuffleDependency --> coGroupedRDD --> Cogroup --> fullOuterJoin/rightOuterJoin/leftOuterJoin

Cogroup --> join

ShuffleDependency --> ShuffledRDD --> combineByKeyWithClassTag --> combineByKey

combineByKeyWithClassTag --> reduceByKey

ShuffledRDD --> Coalesce

ShuffledRDD --> sortByKey --> sortBy

3.Shuffle Dependency构造

1. A single key-value pair RDD, i.e. RDD[Product2[K, V]];

2. Partitioner (available as partitioner property);

  • 用来将record映射到具体的partition的方法。
  • 接口
    • numberPartitions
    • getPartition
  • 经典实现
    • HashPartitioner

3. Serializer;

4. Optional key ordering (of Scala’s scala.math.Ordering type);

5. Optional Aggregator;

  • 在map侧合并部分record的函数。
  • 接口
    • createCombiner:只有一个value的时候初始化的方法;
    • mergeValue:合并一个value到Aggregator中;
    • mergeCombiners:合并两个Aggregator。

6. mapSideCombine flag which is disabled (i.e. false) by default。

四、shuffle过程

1.spark中的shuffle变迁过程

1.HashShuffle 

  • 写数据

image.png 每个partition会映射到一个独立的文件。

优点:不需要排序

缺点:打开,创建的文件过多

  • 写数据优化

image.png   每个partition会映射到一个文件片段。

2.SortShuffle

  • 写数据

image.png

每个task生成一个包含所有partition数据的文件。

优点:打开的文件少、支持map-side combine

缺点:需要排序

3.TungstenSortShuffle

优点:更快的排序效率,更高的内存利用效率

缺点:不支持map-side combine

4.读数据

image.png

每个reduce task分别获取所有map task生成的属于自己的片段。

2.Shuffle过程的触发流程

graph TD
CollectAction --> SubmitJob --> GetDependencies --> RegisterShuffle

3.Register Shuffle

1. 由action算子触发DAG Scheduler进行shuffle register;

2. Shuffle Register会根据不同的条件决定注册不同的ShuffleHandle。

1.ShuffleHandle的创建

image.png

三种ShuffleHandle对应了三种不同的ShuffleWriter的实现:

  • BypassMergeSortShuffleWriter:HashShuffle

  • UnsafeShuffleWriter:TunstonShuffle

  • SortSHuffleWriter:SortShuffle

2.write的实现

1.BypassMergeSortShuffleWriter

image.png

  • 不需要排序,节省时间

  • 写操作的时候会打开大量文件

2.UnsafeShuffleWriter

image.png

  • 使用类似内存页储存序列化数据

  • 数据写入后不再反序列化

image.png

  • 只根据partition排序 Long Array

  • 数据不移动

3.SortSHuffleWriter

image.png

  • 支持combine

  • 需要combine时,使用PartitionedAppendOnlyMap,本质是个HashTable

  • 不需要combine时PartitionedPairBuffer本质是个array

3.reader的实现

 

1.网络时序图

image.png

使用netty(对外内存)作为网络框架提供网络服务,并接受reducetask的fetch请求,位置信息记录在MapOutputTracker中。主要会发送两种类型的请求:

  • 首先发起openBlocks请求获得streamId;

  • 然后再处理Chunk请求或Stream请求。

2.ShuffleBlockFetchIterator

image.png

  • 区分local和remote节省网络消耗;

  • 防止OOM

    • maxBytesInFlight:限制获取数据块的大小;

    • maxReqsInFlight:限制请求的数量;

    • maxBlocksInFlightPerAddress:每一个地址上获取的Blocks的数量;

    • maxReqSizeShuffleToMem:在Memory中最大的请求数量;

    • maxAttemptsOnNettyOOM:可知OOM次数。

3.External Shuffle Service

作用:解耦数据计算和数据读取服务。

image.png ESS作为一个存在于每个节点上的agent为所有Shuffle Reader提供服务,从而优化了Spark作业的资源利用率,MapTask在运行结束后可以正常退出。

 

为了解决Executor为了服务数据的fetch请求导致无法退出问题,我们在每个节点上部署一个External Shuffle Service,这样产生数据的Executor在不需要继续处理任务时,可以随意退出。

4.shuffle优化技术

1. Zero Copy

DMA(Direct Memory Access):直接存储器存取,是指外部设备不通过CPU而直接与系统内存交换数据的接口技术。

1.不使用Zero Copy

image.png

包含了4次上下文切换,也包含了4次对数据的拷贝,影响性能。

2.使用sendfile

image.png

减少了上下文切换次数(2次),也减少了数据的拷贝次数(3次)。

3.sendfile+DMA gather copy

image.png

2次上下文切换,2次对数据的拷贝。

2. Netty Zero Copy

  • 可堆外内存,避免 JVM 堆内存到堆外内存的数据拷贝。

  • CompositeByteBuf 、 Unpooled.wrappedBuffer、 ByteBuf.slice ,可以合并、包装、切分数组,避免发生内存拷贝。

  • Netty 使用 FileRegion 实现文件传输,FileRegion 底层封装了 FileChannel#transferTo() 方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝。

5. Spark3.0中shuffle过程存在的问题

  • 数据存储在本地磁盘,没有备份

  • IO 并发:大量 RPC 请求(M*R)

  • IO 吞吐:随机读、写放大(3X)

  • GC 频繁,影响 NodeManager

6. Shuffle优化

1.避免shuffle,使用broadcast替代join。

2.使用可以map-side预聚合的算子。

3.Shuffle参数优化。

  • spark.default.parallelism && spark.sql.shuffle.partitions

    • 默认并发度;
    • 并发度过高,随机读问题;
    • 并发度过低,作业处理时间延长。
  • spark.hadoopRDD.ignoreEmptySplits

    • 减少partition数量,空文件或空数据不生成partition。
  • spark.hadoop.mapreduce.input.fileinputformat.split.minsize

    • 减少partition数量,合并partition。
  • spark.sql.file.maxPartitionBytes

    • 规定Task处理的数据量,生成合适的partition大小。
  • spark.sql.adaptive.enabled && spark.sql.adaptive.shuffle.targetPostShuffleInputSize

    • 动态调整Reduce阶段partition的数量。
  • spark.reducer.maxSizeInFlight

  • spark.reducer.maxReqsInFlight

  • spark.reducer.maxBlocksInFlightPerAddress

7.  Shuffle倾斜优化

image.png

1.倾斜影响

  • 作业运行时间变长

  • Task OOM导致作业失败

2.解决倾斜的方法

  • 增大并发度

image.png

优点:足够简单

缺点:只缓解、不根治

  • AQE

AQE根据shuffle文件统计数据自动检测倾斜数据,将那些倾斜的分区打散成小的子分区,然后各自进行join。

image.png

image.png

五、Push Shuffle

1.为什么需要Push Shuffle

  • Avg lO size太小,造成了大量的随机lO,严重影响磁盘的吞吐;

  • M*R次读请求,造成大量的网络连接,影响稳定性。

2.Magnet

1.Magnet原理

image.png

  • Spark driver组件,协调整体的shuffle操作;

  • map任务的shuffle writer过程完成后,增加了一个额外的操作push-merge,将数据复制一份推到远程shuffle服务上;

  • magnet shuffle service是一个强化版的ESS。将隶属于同一个shuffle partition的block,会在远程传输到magnet后被merge到一个文件中;

  • reduce任务从magnet shuffle service接收合并好的shuffle数据。

image.png

  • bitmap:存储已merge的mapper id,防止重复merge;

  • position offset:如果本次block没有正常merge,可以恢复到上一个block的位置;

  • currentMapld:标识当前正在append的block,保证不同mapper 的block能依次append。

2.Magnet可靠性

  • 如果Map task输出的Block没有成功Push到magnet上,并且反复重试仍然失败,则reducetask直接从ESS上拉取原始block数据;

  • 如果magnet上的block因为重复或者冲突等原因,没有正常完成merge的过程,则reducetask直接拉取未完成merge的block;

  • 如果reduce拉取已经merge好的block失败,则会直接拉取merge前的原始block本质上,magnet中维护了两份shuffle数据的副本。

3.Cloud Shuffle Service

1.Cloud Shuffle Service思想

  image.png

2.Cloud Shuffle Service架构

image.png

  • Zookeeper WorkerList [服务发现]

  • CSS Worker [Partitions / Disk | Hdfs]

  • Spark Driver [集成启动 CSS Master]

  • CSS Master [Shuffle 规划 / 统计]

  • CSS ShuffleClient [Write / Read]

  • Spark Executor [Mapper + Reducer]

3.Cloud Shuffle Service 读写流程

image.png

4.Cloud Shuffle Service AQE

image.png

  • 在聚合文件时主动将文件切分为若干块,当触发AQE时,按照已经切分好的文件块进行拆分。

  • —个Partition会最终对应到多个Epoch file,每个EPoch目前设置是512MB。


参考文章:juejin.cn/post/712390…