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

196 阅读6分钟

这是我参与「第四届青训营」笔记创作活动的的第6天,以下是我的课堂笔记。 本次课程主要分为四个大板块:
1. Shuffle概述
2. Shuffle算子
3. Shuffle过程
4. Push Shuffle

1. Shuffle概述

1.1 MapReduce概述

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

1.2 Map阶段

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

image.png

1.3 Shuffle阶段

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

image.png

1.4 Reduce阶段

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

image.png 拿到sum值

1.5 为什么shuffle 对性能非常重要

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

1.6 总结

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

2. Shuffle算子

2.1 Shuffle算子分类

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

image.png

2.2 Shuffle算子应用

  • Spark源码中RDD的单元测试
  • Spark源码中PairRDDFunctions的单元测试

image.png

2.3 Spark中对shuffle的抽象–宽依赖、窄依赖

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

2.3 算子内部的依赖关系

- ShuffleDependency
- coGroupedRDD
. Cogroup
. fullOuterJoin、rightOuterJoin、leftOuterJoin
. join
- ShuffledRDD
. combineByKeyithClassTag
combineByKey
reduceBuo.
. sortByKey
sortBy

2.4 Shuffle Dependency构造

  • Asingle 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.

3. Shuffle过程

3.1 Hash Shuffle -写数据

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

image.png

3.2 Hash Shuffle -写数据优化

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

image.png

3.3 Sort shuffle :写数据

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

image.png

3.4 Shuffle -读数据

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

image.png

3.5 Shuffle Handle的创建

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

image.png

3.6 Shuffle Handle 与Shuffle Writer的对应关系

image.png

3.7 Writer 实现-BypassMergeShuffleWriter

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

image.png

3.8 Writer实现-UnsafeShuffleWriter

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

image.png

3.9 Writer 实现- UnsafeShuffleWriter

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

image.png

3.10 Reader 实现-网络时序图

  • 使用基于netty的网络通信框架
  • 位置信息记录在MapOutputTracker中
  • 主要会发送两种类型的请求
    • OpenBlocks请求
    • Chunk请求或Stream请求

image.png

3.11 Reader实现- ShuffleBlockFetchIterator

-区分local和remote节省网络消耗
防止OOM

  • maxBytesInFlight
  • maxReqsInFlight
  • maxBlocksInFlightPerAddress
  • maxReqSizeShuffleToMem
  • maxAttemptsOnNettyOOM image.png

3.12 Read 实现-External Shuffle Service

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

image.png

3.13 Shuffle优化使用的技术- Zero Copy

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

image.png

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

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

3.15 常见问题

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

3.16 Shuffle优化

  • 避免shuffle
    • 使用broadcast替代join

image.png

3.17 Shuffle优化

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

image.png

image.png

3.18 Shuffle参数优化

  • spark.default.parallelism && spark.sql.shuffle.partitions
  • spark.hadoopRDD.ignoreEmptySplits
  • spark.sql.file.maxPartitionD.peeinputTormat.split.minsize
  • spark.sql.adaptive.enabled && spark.sql.adaptive.shuffle.targetPostShuffleInputSize. spark.reducer.maxSizeInFlight
  • spark.reducer.maxReqsInFlight
    • spark.reducer.maxBlocksInFlightPerAddress

3.19 常见的倾斜处理办法

  • 提高并行度
    • 优点:足够简单
    • 缺点∶只缓解、不根治

image.png

3.20 Spark AQE Skew Join

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

image.png

4. Push Shuffle

4.1 为什么需要Push Shuffle ?

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

image.png

4.2 Push Shuffle的实现

· Facebook : cosco
. LinkedIn : magnet. Uber : Zeus
· Alibaba : RSS
. Tencent : FireStorm
. Bytedance : CSS
. Spark3.2 : push based shuffle\

4.3 Magnet 实现原理

  • 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

4.3 Magnet 实现原理

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

image.png

4.4 Magnet可靠性

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

4.6 Cloud Shuffle Service架构

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

image.png

5. 总结

1.Shuffle 概述
(1)什么是shuffle ,shuffle的基本流程
(2)为什么shuffle对性能影响非常重要
2. Shuffle算子
(1)常见的的shuffle算子
(2)理解宽依赖和窄依赖,ShuffleDependency及其相关组件
3. Shuffle过程
(1)Spark中shuffle实现的历史
(2)Spark中主流版本的shuffle写入和读取过程
4. Push shuffle
(1) Magnet Push Shuffle的设计思路
(2) Cloud Shuffle Service的设计实现思路\