Spark Shuffle原理过程实例详解

302 阅读4分钟

最近在极客时间学习了吴磊老师的Spark课程,结合网上博客提到的原理过程,这里做一个梳理记录,方便以后翻看。

Spark中Shuffle的含义是集群范围内跨节点、跨进程的数据分发,它是Map阶段和Reduce阶段数据传递的桥梁。在比较早的Spark版本中默认使用的是Hash Shuffle,后来因为这个过程中产生的小文件过多,影响磁盘IO以及产生OOM的问题,产生了Sort Shuffle,这里主要是根据Sort Shuffle中的普通模式做实例讲解,普通模式原理过程如图所示:

image.png

众所周知Shuffle阶段主要是包括Shuffle Write极端和Shuffle Read阶段,阶段之间界限如下图所示:

image.png Shuffle Write阶段主要是将Map阶段经过初步聚合的数据分类合并,首先将数据读入buffer中形成键值对形式的map数据结构,Map 结构的 Key 是(Reduce Task Partition ID,Record Key),而 Value 是原数据记录中的数据值,当 Map 结构被灌满之后,Spark 根据主键对 Map 中的数据记录做排序,然后把所有内容溢出到磁盘中的临时文件,当所有的数据记录都写入磁盘文件后接下来将所有的磁盘文件记录做排序合并到一个磁盘文件中,并且针对该磁盘文件形成索引文件,记录合并之前每个文件记录的位置,那每个key应该被哪个ReduceTask读取呢?这里用到的是公式: P = Hash(Record Key) % N

Shuffle Read阶段主要是根据索引文件读取磁盘数据文件,从每个磁盘文件中读取属于自己Partition ID的数据记录,读取完成之后接下来就是下一阶段Reduce Task。

实例: 接下来以常见的WordCount为例来跟踪每一阶段Executor所做的事情,这里假设有3个Executor,每个Executor在Map阶段已经将数据读入并完成了初步聚合,即Executor1的数据记录包含(Compute,2),(icon,1),(Spark,1),(is,2)。Executor2中包含的数据记录是(can,2),(ip,1),(Streaming,1),(in,3),Executor3中包含的数据记录(cool,1)和(Scala,2),3个Reduce Task,如下图所示:

image.png

接下来就是Shuffle Write阶段首先将Executor1中的数据记录读入buffer缓存中,假设Map缓存默认大小只能保留4条数据记录,那么此时buffer中的数据如下表: (partition ID,key) Value

(partition ID,key)Value
(P2,compute)2
(P1,icon)1
(P0,Spark)1
(P1,is)2

这里(Spark,1)这条记录按照key值也就是Spark经过哈希之后除以N(也就是3)之后分配给了P0,其他记录以此类推,当Executor1中的记录都读入buffer中以后接下来读取Executor2中的数据记录时发现buffer缓存已经满了,于是将缓存中的数据记录排序然后将内容写到磁盘中临时文件第一个data.temp文件,清空buffer缓存,接下来读取Executor2中的数据记录,同样是排序之后形成写入磁盘形成第二个data.temp文件,最后Executor3数据读入缓存之后所有的数据记录都形成了统一的Map结构,最后将缓存数据 第一个data.temp文件 第二个data.temp文件读取并进行归并算法排序合并形成最终的data数据文件和与之对应的index文件,如下图所示,至此Shuffle Write阶段完成。

image.png

Shuffle Write 过程中生成中间文件的详细过程,归纳起来,这个过程分为 4 个步骤:

  1. 对于数据分区中的数据记录,逐一计算其目标分区,然后填充内存数据结构;
  2. 当数据结构填满后,如果分区中还有未处理的数据记录,就对结构中的数据记录按(目标分区 ID,Key)排序,将所有数据溢出到临时文件,同时清空数据结构;
  3. 重复前 2 个步骤,直到分区中所有的数据记录都被处理为止;
  4. 对所有临时文件和内存数据结构中剩余的数据记录做归并排序,生成数据文件和索引文件。

再接着就是Shuffle Read阶段,Reduce Task 通过 index 文件来“定位”属于自己的数据内容,并通过网络从不同节点的 data 文件中下载属于自己的数据记录,注意在Map Task计算阶段没有发现某些Reduce Task数据,那么index中的索引会一直顺延。

总结:有些地方可能没有写清楚,没看明白的地方可以去吴老师的课程详细了解,time.geekbang.org/column/arti… ,网上关于Shuffle的原理过程有很多博客讲解,讲得比较全的是juejin.cn/post/684490… 本文借用一下这位大佬的图片配合进行说明。从过程来看Shuffle Read阶段应该就是Reduce Task 读取Shuffle中间文件,所以Read阶段应该就是Reduce阶段,但是Write阶段不是Map阶段。有写得不对的地方轻喷,谢谢,本文只做学习记录之用,后续了解清楚之后再补充完善。