Spark Shuffle机制

Shuffle机制

Apache Spark是一个强大的分布式计算框架,它能够高效地处理大规模数据集并加速数据处理过程。其中一个关键的特性就是其Shuffle机制,理解Spark的Shuffle机制对于理解Spark作业的执行至关重要。本文将分别介绍Spark的Shuffle Write阶段和Shuffle Read阶段,并在最后与MapReduce Shuffle机制进行比较。

简介

Shuffle解决的是上下游stage之间传递数据的问题。Shuffle机制分为Shuffle Write和Shuffle Read两个阶段,前者主要解决上游Stage输出数据的分区问题,后者主要解决下游Stage从上游Stage获取数据、重新组织、并为后续操作提供数据的问题。

以join操作为例的Spark Shuffle过程:

Shuffle Write

Spark的Shuffle Write过程包含数据聚合,排序,分区三个步骤,其中分区是必备步骤,聚合和排序是可选步骤。

  • 聚合:进行聚合combine操作的目的是减少Shuffle的数据量。只有包含聚合函数的数据操作才需要进行Shuffle Write时的combine,例如aggregateByKey(), reduceByKey(), distinct()等。
  • 排序:可根据partitionId+key或者只根据partitionId进行排序
  • 分区(Required)。在partition时,Spark根据partitionId将record依次输出到不同的buffer中,每当buffer填满就将record溢写到磁盘上的分区文件中。使用buffer的原因是map()输出record的速度很快,需要进行缓冲来减少磁盘I/O

下图展示了一个包含聚合和排序操作的Shuffle Write流程:

注:Shuffle Write的分区个数与下游Stage的task个数一致,这个分区个数可以由用户自定义,如groupByKey(numPartitions)中的numPartitions。如果用户没有定义,则默认分区个数是父RDD的分区个数的最大值

Shuffle Read

Spark的Shuffle Read过程包含数据获取,聚合,排序三个步骤。其中数据获取是必备步骤,聚合和排序是可选步骤。

  • 数据获取(Required):从上一个stage中的task获取record,并将record输出到buffer中,下一步操作就可以直接从buffer中获取数据。
  • 聚合:获取record后,Spark建立一个类似HashMap的数据结构(ExternalAppendOnlyMap)对buffer中的record进行聚合。HashMap中的key是record中的key,value是经过聚合函数计算后的结果。
  • 排序:如果需要对key进行排序,则建立一个Array结构,读取HashMap中的record,并对record按key进行排序。

下图展示了一个包含聚合和排序操作的Shuffle Read流程:

注:Shuffle中使用的数据结构都试图在内存中进行聚合和排序,如果内存放不下,则进行扩容。如果扩容还放不下,就将数据spill到磁盘上,最后将磁盘和内存中的数据进行merge得到最终结果。

与MapReduce Shuffle的区别

  • MapReduce不能在线聚合,即无论是map端还是reduce端,都是先将数据存到buffer或spill到磁盘后,再执行聚合操作。而Spark是随着map的不断输出,在内存中使用hashMap来进行聚合的。
  • MapReduce在shuffle write时严格按照key排序,但对于groupByKey()这样的操作不需要严格按照key进行排序。而Spark在shuffle write时的排序比较灵活,可以根据partitionId+key排序,也可以根据partitionId排序,或者不排序。

参考资料

  1. 许利杰,方亚芬. 大数据处理框架Apache Spark设计与实现[M]. 电子工业出版社, 2021.