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

61 阅读6分钟

「大数据 Shuffle 原理与实践」

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

01.Shuffle概述

MapReduce概述

202207311444324.png

  • 2004年谷歌发布了《MapReduce:Simplified Data Processing on LargeClusters》论文
  • 在开源实现的MapReduce中,存在Map.Shuffle、Reduce三个阶段。

Map阶段

Map阶段,是在单机上进行的针对─小块数据的计算过程

Shuffle阶段

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

Reduce过程

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

为什么shuffle 对性能非常重要

  • M*R次网络连接
  • 大量的数据移动
  • 数据丢失风险
  • 可能存在大量的排序操作
  • 大量的数据序列化、反序列化操作
  • 数据压缩
  • 202208010005752.png

总结

在大数据场景下,数据 shuffle表示了不同分区数据交换的过程,不同的shuffle策略性能差异较大。

目前在各个引擎中shuffle都是优化的重点,在spark框架中,shuffle是支撑spark进行大规模复杂数据处理的基石。

image-20220731144834415

02.Shuffle算子

Shuffle算子分类

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

202207311449267.png

Spark中对shuffle的抽象

202207311451611.png

宽依赖、窄依赖

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

算子内部的依赖关系 Shuffle Dependency

  • coGroupedRDD

    • Cogroup

      • fullOuterJoin、rightOuterJoin、leftOuterJoin
      • join
  • ShuffledRDD

    • combineByKeyWithClassTag

      • combineByKey
      • reduceByKey
    • Coalesce

    • sortByKey

      • sortBy
  • 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.
  • Partitioner

    • 用来将record映射到具体的partition的方法

    • 接口

      • numberPartitions
      • getPartition
  • Aggregator

    • 在map侧合并部分record的函数

    • 接口

      • createCombiner:只有一个value的时候初始化的方法
      • mergeValue:合并一个value到Aggregator中
      • mergeCombiners:合并两个Aggregator

03.Shuffle过程

Shuffle实现的发展历程

  • Spark 0.8及以前Hash Based Shuffle
  • Spark 0.8.1为Hash Based Shuffle引入File
  • Consolidation机制
  • Spark 0.9引入ExternalAppendOnlyMap
  • Spark 1.1引入 Sort Based Shuffle,但默认仍为Hash Based Shuffle
  • Spark 1.2默认的 Shuffile方式改为Sort Based Shuffle
  • Spark 1.4引入Tungsten-Sort Based Shuffle
  • Spark 1.6 Tungsten-Sort Based Shuffle 并入 Sort Based Shuffle
  • Spark 2.0 Hash Based Shuffle退出历史舞台

Hash Shuffle

写数据

每个partition会映射到一个独立的文件

image-20220801000734291

Hash Shuffle -写数据优化

每个partition会映射到一个文件片段

202208010008790.png

Sort shuffle

写数据

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

image-20220801000902018

Shuffle -读数据

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

202208010009511.png

Shuffle过程的触发流程

image-20220801001009058

Shuffle Handle的创建

202208010010981.png

Register Shuffle时做的最重要的事情是根据不同条件创建不同的shuffle Handle

Shuffle Handle 与Shuffle Writer的对应关系

image-20220801001118664

Writer 实现 - BypassMergeShuffleWriter

image-20220731222453977

  • 不需要排序,节省时间
  • 写操作的时候会打开大量文件
  • 类似于Hash Shuffle

Writer 实现 - UnsafeShuffleWriter

image-20220731222546367

  • 使用类似内存页储存序列化数据
  • 数据写入后不再反序列化

202207312226375.png

  • 只根据partition排序 Long Array
  • 数据不移动

3.7 Writer 实现 - SortShuffleWriter

  • 支持combine
  • 需要combine时,使用PartitionedAppendOnlyMap,本质是个HashTable
  • 不需要combine时PartitionedPairBuffer本质是个array

image-20220731222858015

Reader 实现 - 网络时序图

  • 使用基于netty的网络通信框架

  • 位置信息记录在MapOutputTracker中

  • 主要会发送两种类型的请求

    • OpenBlocks请求
    • Chunk请求或Stream请求

image-20220731223201776

Reader 实现 – ShuffleBlockFetchlterator

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

  • 防止OOM

    • maxByteslnFlight
    • maxReqslnFlight
    • maxBlockslnFlightPerAddress
    • maxReqSizeShuffleToMem
    • maxAttemptsOnNettyOOM

202207312233000.png

Read实现 - External Shuffle Service

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

image-20220731223906275

Shuffle优化使用的技术 - Zero Copy

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

image-20220731224114994

Shuffle优化使用的技术: Netty Zero Copy

  • 可堆外内存,避免JVM堆内存到堆外内存的数据拷贝。
  • CompositeByteBufUnpooled.wrappedBufferByteBuf.slice,可以合并、包装、切分数组,避免发生内存拷贝
  • Netty使用FileRegion 实现文件传输,FileRegion底层封装了FileChannel#transferTo()方法,可以将文件缓冲区的数据直接传输到目标Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝

常见问题

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

Shuffle优化

  • 避免shuffle

    • 使用broadcast替代join

202207312251866.png

  • 使用可以map-side预聚合的算子

    • 202207312252640.png

Shuffle参数优化

spark.default.parallelism && spark.sql.shuffle.partitions
spark.hadoopRDD.ignoreEmptySplits
spark.hadoop.mapreduce.input.fileinputformat.split.minsize
spark.sqI.file.maxPartitionBytes
spark.sql.adaptive.enabled && spark.sql.adaptive.shuffle.targetPostShuffleInputSize
spark.reducer.maxSizeInFlight
spark.reducer.maxReqsInFlight
spark.reducer.maxBlockslnFlightPerAddress

Shuffle倾斜优化

  • 什么叫shuffle倾斜

  • 倾斜影响

    • 作业运行时间变长
    • Task OOM导致作业失败
  • 提高并行度

    • 优点:足够简单
    • 缺点:只缓解、不根治!

Spark AQE Skew Join

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

image-20220731225901556

参数优化

image-20220731225958115

202207312300322.png

Push Shuffle

为什么需要Push Shuffle ?

  • Avg lO size太小,造成了大量的随机lO,严重影响磁盘的吞吐
  • M*R次读请求,造成大量的网络连接,影响稳定性

image-20220731230239315

Push Shuffle的实现

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

Magnet 实现原理

  • Spark driver组件,协调整体的shuffle操作
  • map任务的shuffle writer过程完成后,增加了一个额外的操作push-merge,将数据复制一份推到远程shuffle服务上
  • magnet shuffle service是一个强化版的ESS.将隶属于同一个shuffle partition的block,会在远程传输到magnet后被merge到一个文件中
  • reduce任务从magnet shuffle service接收合并好的shuffle数据

202207312305741.png

  • bitmap:存储已merge的mapper id,防止重复merge
  • position offset:如果本次block没有正常merge,可以恢复到上一个block的位置
  • currentMapld:标识当前正在append的block,保证不同mapper的block能依次append

image-20220731230710914

Magnet 可靠性

  • 如果Map task输出的Block没有成功Push到magnet上,并且反复重试仍然失败,则reducetask直接从ESS上拉取原始block数据
  • 如果magnet上的block因为重复或者冲突等原因,没有正常完成merge的过程,则reducetask直接拉取未完成merge的block
  • 如果reduce拉取已经merge好的block失败,则会直接拉取merge前的原始block
  • 本质上,magnet中维护了两份shuffle数据的副本

课程总结

Shuffle 概述

  1. 什么是shuffle,shuffle的基本流程
  2. 为什么shuffle对性能影响非常重要

Shuffle算子

  1. 常见的shuffle算子
  2. 理解宽依赖和窄依赖,ShuffleDependency及其相关组件

Shuffle过程

  1. Spark中shuffle实现的历史
  2. Spark中主流版本的shuffle写入和读取过程

Push shuffle

  1. Magnet Push Shuffle 的设计思路
  2. Cloud Shuffle Service 的设计实现思路