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

109 阅读5分钟

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

1. Shuffle 概述

1.1. MapReduce 概述

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

image.png

1.1. Map 阶段

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

image.png

1.2. Shuffle 阶段

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

image.png

1.3. Reduce 过程

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

image.png

1.4. 为什么Shuffle 对性能非常重要

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

image.png

1.5. 总结

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

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

image.png

2. Shuffle 算子

2.1. Shuffle 算子分类

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

image.png

2.1. Shuffle 算子应用

image.png

2.2. Spark中对Shuffle的抽象 - 宽依赖、窄依赖

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

image.png

2.2. 算子内部的依赖关系

  • ShuffleDependency
    • CoGroupedRDD
      • Cogroup
        • fullOuterJoin、rightOuterJoin、leftOuterJoin
        • join
    • shuffledRDD
      • combineByKeyWithClassTag
        • combineByKey
        • reduceByKey
      • Colaesce
      • sortByKey
        • sortBy

2.2.1. Shuff Dependency 构造

  • A single key-value pair RDD
  • Partitioner
  • Serializer
  • Optional key ordering
  • Optional Aggregator
  • mapSideCombine flag which is disabled by default

2.2.1. Shuffle Dependency 构造 - Partitioner

  • 两个接口
    • numberPartitions
    • getPartition
  • 经典实现
    • HashPartition

image.png

image.png

2.2.1. Shuffle Dependency 构造 - Aggregator

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

3. Shuffle 过程

Shuffle实现的发展过程

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

3.1. Hash Shuff - 写数据

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

image.png

3.1. Hash Shuffle - 写数据的优化

每个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

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.7. Writer 实现 - UnsafeShuffleWriter

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

image.png

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

image.png

3.7. Writer实现 - SortShuffleWriter

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

image.png

3.8. Reader实现 - 网络时序图

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

image.png

3.8. Reader实现 - ShuffleBlockFetchIterator

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

image.png

3.8. Reader 实现 - External Shuffle Service

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

image.png

3.9. Shuffle 优化使用的计数 - Zero Copy

image.png

3.9. Shuffle 优化使用的技术 - Netty Zero Copy

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

3.10 常见问题

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

3.11. Shuffle优化

  • 避免Shuffle
    • 使用broadcast代替join

image.png

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

image.png

3.12. Shuffle参数优化

image.png

3.13. Shuffle倾斜优化

  • 什么叫shuffle倾斜
  • 倾斜影响
    • 作业运行时间变长
    • Task OOM导致作业失败

image.png

3.13. 常见的倾斜处理办法

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

image.png

3.13. Spark AQE Skew Join

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

image.png

3.14. 案例 - 参数优化

image.png

3.15. 参数调整

image.png

4. Push Shuffle

4.1. 为什么需要Push Shuffle

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

image.png

4.2. Push Shuffle 的实现

image.png

4.3. Magnet实现原理

image.png

image.png

4.4. Magnet 可靠性

image.png

4.5. Cloud Shuffle Service 思想

image.png

4.6. Cloud Shuffle Service 架构

image.png

4.6.1. Cloud Shuffle Service 写入流程

image.png

4.6.2. Cloud Shuffle Service 读取流程

image.png

4.6.3. Cloud Shuffle Service AQE

image.png

4.7. 实践案例 - CSS 优化

image.png