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

108 阅读2分钟

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

shuffle概述

MapReduce 的三个阶段

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

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

  • M*R次网络连接
  • 大量数据移动
  • 数据移动和计算的过程中,存在丢失风险
  • 可能存在大量排序操作
  • 大量的数据序列化、反序列化操作
  • 数据压缩(如果数据量非常大,存储中可能涉及)

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


shuffle算子

spark中会产生shuffle的算子分为4类

  • repartition (coalesce, repartition)
  • ByKey (groupByKey, reduceByKey, aggregateByKey, etc.)
  • join (join, subtract, cogroup, etc.)
  • distinct

算子内部的依赖关系 ShuffleDependency

  • CoGroupedRDD
  • ShuffledRDD

ShuffleDependency 的构造

  • 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

shuffle过程

Hash Shuffle

  • 写数据:每个partition会映射到一个独立的文件。每个Map Task都会给每个partition创建一个buffer,写满后flush到磁盘
  • 写数据优化:每个partition会映射到一个文件片段
  • 优点:不需要排序
  • 缺点:打开、创建的文件过多

Sort Shuffle

  • 每个task生成一个包含所有 partition 数据的文件
  • 优点:打开的文件少、支持map-side combine
  • 缺点:需要排序

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

Shuffle过程的触发流程:Collect Action -> Submit Job -> Get Dependencies -> RegisterShuffle

  • Register Shuffle时做的最重要的事情是根据不同条件创建不同的 Shuffle Handle
  • 三种ShuffleHandle对应了三种不同的ShuffleWriter的实现
    • BypassMergeSortShuffleWriter:BypassMergeSortShuffleHandle
    • UnsafeShuffleWriter:SerializedShuffleHandle
    • SortSHuffleWriter:BaseShuffleHandle

Push based shuffle

spark3.2中引入的

之前Shuffle的问题

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

为什么需要push shuffle?

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