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

78 阅读4分钟

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

课程目录

1.Shuffle概述

2.Shuffle算子

3.Shuffle过程

4.Push Shuffle

1.Shuffle概述

1.1 MapReduce概述

  • Map阶段:是在单机上进行的针对一小块数据的计算过程
  • Shuffle阶段:在map阶段的基础上,进行数据移动,为后续的reduce阶段做准备
  • Reduce阶段:对移动后的数据进行处理,依然是在单机上处理一小份数据

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

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

1.总结

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

2.Shuffle算子

2.1 Shuffle算子分类

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

image.png

2.1.1 Shuffle算子应用

image.png

2.2 Spark中对shuffle的抽象

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

算子内部的依赖关系

ShuffleDependency

  • CoGroupedRDD
  • ShuffledRDD

2.2.1 Shuffle Dependency构造

image.png

Partitioner

两个接口

  • numberPartitions
  • getPartition 经典实现
  • HashPartitioner

Aggregator

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

3.Shuffle过程

Shuffle实现的发展历程

image.png

3.1 Hash Shuffle

3.1.1 写数据

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

image.png

3.1.2 写数据优化

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

image.png

3.2 Sort shuffle:写数据

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

image.png

3.3 Shuffle -读数据

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

image.png

3.4 Shuffle过程的触发流程

image.png

graph TD
A[Collect Action]-->B[SubmitJob] --> C[GetDependencies] --> D[RegisterShuffle]

3.5 Shuffle Handle的创建

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

3.6 Shuffle Handle与Shuffle Writer的对应关系

image.png

3.7 Writer实现

3.7.1 BypassMergeShuffleWriter

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

3.7.2 UnsafeShuffleWriter

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

3.7.3 UnsafeShuffleWriter

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

3.7.4 SortShuffleWriter

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

3.8 Reader实现

3.8.1 网络时序图

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

3.8.2 ShuffleBlockFetchlterator

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

image.png

3.8.3 External Shuffle Service

image.png

3.9 Shuffle优化使用的技术

3.9.1 Zero Copy

不使用zero copy

image.png 使用sendfile

image.png 使用sendfile+DMA gather copy

image.png

3.9.2 Netty Zero Copy

image.png

3.10 常见问题

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

3.11 Shuffle 优化

  • 避免shuffle
  • 使用broadcast替代join
  • 使用可以map-side预聚合的算子

3.12 Shuffle参数优化

image.png

3.13 Shuffle倾斜优化

3.13.1 倾斜影响

  • 作业运行时间变长
  • Task OOM导致作业失败

3.13.2 常见的倾斜处理方法

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

3.13.3 Spark AQE Skew Join

image.png

3.14 案例-参数优化

image.png

3.15 参数调整

  • spark.sql.adaptive.shuffle.targetPostShuffleInputSize:64M -> 512M
  • spark.sql.files.maxPartitionBytes:1G -> 40G image.png

4.Push Shuffle

4.1 为什么需要Push Shuffle

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

4.2 Push Shuffle的实现

image.png

4.3 Magnet实现原理

image.png

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

4.4 Magnet可靠性

image.png

4.5 Cloud Shuffle Service思想

image.png

4.6 Cloud Shuffle Service架构

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

4.6.1 Cloud Shuffle Service写入流程

image.png

4.6.2 Cloud Shuffle Service读取流程

image.png

4.6.3 Cloud Shuffle Service AQE

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

4.7 实践案例-CSS优化

  • XX业务 小时级任务(1.2W cores)
  • 混部队列2.5h->混部队列+CSS1.3h(50%提升)

image.png

本次课程个人总结

大数据Shuffle原理与实践.jpg