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

108 阅读3分钟

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

接着前面的内容,今天我们来探讨一下Shuffle原理

什么是Shuffle

在开源实践的MapReduce当中,存在Map,shuffle,Reduce三个阶段

image.png 我们将一整份数据拆分成多个块,在多个机器上运行,这样就提高处理效率,而这些块中,不同的数据有不同处理方式,Map负责将这些数据筛选出来,然后将筛选后的数据移动到指定位置执行,数据移动的过程就可以称为shuffle,处理完后再整合到一起的过程就可以称为reduce。

为什么Shuffle优化对性能非常重要

在Shuffle过程中,主要有以下可优化的空间:

  • m*r次网络连接
  • 大量数据移动
  • 数据丢失分险
  • 可能存在大量的排序操作
  • 大量的数据序列化,反序列化。
  • 数据压缩

可以看到,任何一项的优化空间都很大,因此对Shuffle就成了各个计算引擎优化的重点,同时在Spark中,Shuffle也是支撑Spark大数据处理的基石。

Shuffle算子

这里我们将Shuffle分为四类

  1. repartition
  2. bykey 聚合操作产生
  3. join 通过join产生
  4. distinst 可以理解成特殊的bykey 主要由以下组成:

image.png

算子产生shuffle要发生数据移动,这个过程在Spark中被抽象成宽,窄依赖也就是上一节课上所提到的。

宽依赖对应对象 ShuffleDependency,它被2个RDD创建,分别是CoGroupedRDD和ShuffledRDD,而这两个RDD,又通过cogroup操作或combine操作生成。

Shuffledependency构造

其中发挥重要作用的是Aggregator结构

  • Aggregator

它把reduce中的工作拿到map上来做。它有3个方法:

  • createcombiner:只有一个value的时候初始化方法
  • mergevalue:合并一个value到Aggregator中
  • mergecombiner 合并两个Aggregator

shuffle过程

  • 通过 Hash Shuffle写数据

image.png

但我们可以看出Hash shuffle写数据生成M x R个文件,这样生成的文件就太多了,文件太多情况会导致OM,所有我们引入了Sort Shuffle.

  • 通过Sort shuffle写数据

image.png

这样做一个task只生成一个文件+index索引文件,大大减少了文件数目。

  • 读数据

image.png 每个Reduce Task分别获取所有map task生成自己的片段。

Shuffle过程触发流程

graph LR
CollectAction --> SubmitJob --> GetDependencies --> RegisterShuffle

我们先来看一下Resigister Shuffle Resigister Shuffle做的事情 最重要就是创建了Shuffle handle,它根据不同场景创建不同Shuffle Handle,如下图:

image.png 每一个Handle都有一个对应的Writer,如下:

image.png 我们来看一下每个Writer是如何实现的。

  • BypassMergeSortShuffleWriter

image.png

他不需要排序,比较节省时间,但写操作时会打开大量文件,其中partition不能太多默认是200,merge运用到zero copy方案。

  • UnsafeShuffleWriter

image.png

不同于上面的实现,这个Writer使用了堆外内存,所一是Unsafe的,使用内存页储存序列化数据,且数据写入后不再反序列化,就减少了序列化反序列化的开销。

说完Writer的实现,再来看一下Reader实现,在Reader中,只有一个方法实现。

  • SortShuffleWriter

image.png 它支持combine,在cmobine时,使用PartitionedAppendOnlyMap,本质上是一个HashTable,不需要Table是就相当与array。