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

152 阅读4分钟

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


0x00 Shuffle 概述

0.1 Mapreduce 概述

map:将数据拆分成分布式状态
shuffle:将拆分后的数据进行分类移动
reduce:将数据分散至机器进行并发操作

5_MapReduce概述.jpeg

0.2 Map阶段

在单机上进行的针对一小块数据的计算过程

0.3 Shuffle阶段

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

0.4 Reduce阶段

对移动后的数据进行处理,依然是在单机上处理一小份数据

0.5 为什么shuffle如此重要?

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


0x01 Shuffle 算子

1.1 常见的触发shuffle的算子

  1. repartition

    coalesce、repartition

  2. ByKey

    groupByKey、reduceByKey、aggregateByKey、combineByKey、sortByKeysortBy

  3. Join

    cogroup、join

  4. Distinct 5_Shuffle算子.png

1.2 算子内部的依赖关系

1.2.1 Shuffle Dependency

  • 创建会产生shuffle的RDD时,RDD会创建Shuffle Dependency来描述Shuffle相关的信息
  • 构造函数:
    • A single key-value pair RDD, i.e. RDD[Product2[K, V]],
    • Partitioner (available as partitioner property),
    • Serializer,
    • Optional key ordering (of Scala’s scala.math.Ordering type),
    • Optional Aggregator,
    • mapSideCombine flag which is disabled (i.e. false) by default.

1.2.2 Partitioner

  • 用来将record映射到具体的partition的方法
  • 接口:
    • numberPartitions
    • getPartition

1.2.3 Aggregator

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

0x02 Shuffle 过程

2.1 HashShuffle

2.1.1 Hash Shuffle - 写数据

每个partition会映射到一个独立的文件 5_Hash.png

2.1.2 Hash Shuffle - 写数据优化

每个partition会映射到一个文件片段 5_Hash1.png

2.2 SortShuffle

2.2.1 Sort Shuffle - 写数据

每个task生成一个包含所有partiton数据的文件 5_sort.png

2.3 Shuffle - 读数据

每个reduce task分别获取所有map task生成的属于自己的片段 5_shuffle读数据.png

2.4 Shuffle 过程的触发流程

5_Shuffle过程触发.png

2.5 Shuffle Handle 的创建

Shuffle Register会根据不同的条件决定注册不同的ShuffleHandle 5_Shuffle Register.jpeg

2.6 ShuffleWriter的实现

三种ShuffleHandle对应了三种不同的ShuffleWriter的实现 5_ShuffleWrite.jpeg

2.7 ShuffleReader网络请求流程

  • 使用netty作为网络框架提供网络服务,并接受reducetask的fetch请求
  • 首先发起openBlocks请求获得streamId,然后再处理stream或者chunk请求 5_网络时序图.png

2.8 Reader实现

2.8.1 Reader实现 - ShuffleBlockFetchIterator

  • 区分local和remote节省网络消耗
  • 防止OOM
    • maxBytesInFlight
    • maxReqsInFlight
    • maxBlocksInFlightPerAddress
    • maxReqSizeShuffleToMem
    • maxAttemptsOnNettyOOM

2.8.2 Reader实现 - External Shuffle Service

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

2.9 shuffle优化

  • 避免shuffle ——使用broadcast替代join
  • 使用可以map-side预聚合的算子
  • Shuffle 参数优化
    • spark.default.parallelism && spark.sql.shuffle.partitions
    • spark.hadoopRDD.ignoreEmptySplits
    • spark.hadoop.mapreduce.input.fileinputformat.split.minsize
    • spark.sql.file.maxPartitionBytes
    • spark.sql.adaptive.enabled && spark.sql.adaptive.shuffle.targetPostShuffleInputSize
    • spark.reducer.maxSizeInFlight
    • spark.reducer.maxReqsInFlight spark.reducer.maxBlocksInFlightPerAddress
  • Shuffle 倾斜优化 5_Shuffle倾斜优化.jpeg
    • 倾斜影响:
      1. 作业运行时间变长
      2. Task OOM导致作业失败
    • 倾斜方法举例:
      1. 增大并发度
      2. AQE
  • 零拷贝
    • sendfile+DMA gather copy
  • Netty 零拷贝
    • 可堆外内存,避免 JVM 堆内存到堆外内存的数据拷贝。
    • CompositeByteBuf 、 Unpooled.wrappedBuffer、 ByteBuf.slice ,可以合并、包装、切分数组,避免发生内存拷贝
    • Netty 使用 FileRegion 实现文件传输,FileRegion 底层封装了 FileChannel#transferTo() 方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝

0x03 Push Shuffle

3.1 为什么需要Push Shuffle

  • 数据存储在本地磁盘,没有备份
  • IO 并发:大量 RPC 请求(M*R)
  • IO 吞吐:随机读、写放大(3X)
  • GC 频繁,影响 NodeManager

3.2 各公司优化思路

  • Facebook: cosco
  • LinkedIn:magnet
  • Uber:Zeus
  • Alibaba: RSS
  • Tencent: FireStorm
  • Bytedance: Cloud Shuffle Service
  • Spark3.2: push based shuffle

3.2 Magnet实现流程

5_主要流程0.png 5_主要流程1.jpeg 主要为边写边push的模式,在原有的shuffle基础上尝试push聚合数据,但并不强制完成,读取时优先读取push聚合的结果,对于没有来得及完成聚合或者聚合失败的情况,则fallback到原模式。

3.3 Cloud Shuffle Service

3.3.1 Cloud Shuffle Service架构

5_Cloud Shuffle Service架构.png

  • Zookeeper WorkerList [服务发现]
  • CSS Worker [Partitions / Disk | Hdfs]
  • Spark Driver [集成启动 CSS Master]
  • CSS Master [Shuffle 规划 / 统计]
  • CSS ShuffleClient [Write / Read]
  • Spark Executor [Mapper + Reducer]

3.3.2 Cloud Shuffle Service写入流程

5_Cloud写入流程.png

3.3.3 Cloud Shuffle Service读取流程

5_Cloud读取流程.png

3.3.4 Cloud Shuffle Service AQE

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