shuffle | 青训营笔记

100 阅读4分钟

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

大数据中的shuffle操作

一、shuffle概述

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

1.mapredu概述

MapReduce分为Map、Shuffle、Reduce三个阶段。

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

image-20220804221403887

为什么shuffle对性能非常重要?
  • M * R次网络连接
  • 大量的数据移动
  • 数据丢失风险
  • 可能存在大量的排序操作
  • 大量的数据序列化、反序列化操作
  • 数据压缩

二、shuffle算子

常见的shuffle算子

  • repartition:coalesce、reparation
  • ByKey:groupByKey、reduceByKey、aggregateByKey、combineByKey、sortByKey、sortby
  • join:cogroup、join、leftOuterJoin、intersection、substract、subtractByKey
  • Distinct:distinct

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:只有一个vakue的时候初始化的方法
  • mergevalue:合并一个value高aggregator
  • mergecombiners:合并链各个aggregator

三、shuffle过程

spark中的shuffle变迁过程

  • hash shuffle

    • 优点:不需要排序
    • 缺点:需要消耗大量资源,创建文件过多
  • sortshuffle

    • 优点:打开文件少、支持map-side combine
    • 缺点:需要排序
  • tungstyensortshuffle

    • 优点:更快的排序效率、更高的内存利用率
    • 缺点:不支持map-sidecombine

register shuffle

由action算子触发DAG Scheduler进行shuffle register,Shuffle Register会根据不同的条件决定注册不同的ShuffleHandle

image-20220804234808448

三种ShuffleHandle对应了三种不同的ShuffleWriter的实现

BypassMergeSortShuffleWriter:HashShuffle

UnsafeShuffleWriter:TunstonShuffle

SortSHuffleWriter:SortShuffle

image-20220804234834863

ShuffleReader网络请求流程

使用netty作为网络框架提供网络服务,并接受reducetask的fetch请求

首先发起openBlocks请求获得streamId,然后再处理stream或者chunk请求

image-20220804234908550

ShuffleBlockFetchIterator

为了区分local和remote节省网络消耗

防止OOM

  • maxBytesInFlight
  • maxReqsInFlight
  • maxBlocksInFlightPerAddress
  • maxReqSizeShuffleToMem
  • maxAttemptsOnNettyOOM

External Shuffle Service

为了解决Executor为了服务数据的fetch请求导致无法退出问题,我们在每个节点上部署一个External Shuffle Service,这样产生数据的Executor在不需要继续处理任务时,可以随意退出。

image-20220804235204268

四、shuffle优化

  1. 避免shuffle ——使用broadcast替代join
  1. 使用可以map-side预聚合的算子
  1. Shuffle 参数优化

    • spark.default.parallelism && spark.sql.shuffle.partitions
    • spark.hadoopRDD.ignoreEmptySplits
    • spark.hadoop.mapreduce.input.fileinputformat.split.minsize
    • spark.sql.file.maxPartitionBytes
    • spark.sql.adaptive.enabled && spark.sql.adaptive.shuffle.targetPostShuffleInputSize
    • spark.reducer.maxSizeInFlight
    • spark.reducer.maxReqsInFlight spark.reducer.maxBlocksInFlightPerAddress
  1. Shuffle 倾斜优化
  1. 零拷贝
  1. Netty 零拷贝

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

五、Push Shuffle

为什么要push shuffle?

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

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-20220804235813445

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

image-20220804235819738

Cloud Shuffle Service架构

image-20220805000530567

Cloud Shuffle Service 读写流程

image-20220805000549820

Cloud Shuffle Service 支持AQE