spark shuffle学习笔记

  • Shuffle就是包裹在各种需要重分区的算子之下的一个对数据进行重新组合的过程。
  • Shuffle 过程本质上都是将 Map 端获得的数据使用分区器进行划分,并将数据发送给对应的 Reducer 的过程

shuffle

  1. shuffle连接map与reduce过程
  2. Map阶段通过shuffle读取数据并输出到对应的Reduce
  3. Reduce阶段负责从Map端拉取数据并进行计算
  4. 在分布式情况下,reduce task需要跨节点去拉取其它节点上的map task结果。这一过程将会产生网络资源消耗和内存,磁盘IO的消耗
  5. 通常shuffle分为两部分:Map阶段的数据准备和Reduce阶段的数据拷贝处理。一般将在map端的Shuffle称之为Shuffle Write,在Reduce端的Shuffle称之为Shuffle Read

hadoop mapReduce shuffle

  1. Shuffle 过程中,提供数据的一端,被称作 Map 端,Map 端每个生成数据的任务称为 Mapper
  2. 接收数据的一端,被称作 Reduce 端,Reduce 端每个拉取数据的任务称为 Reducer
  3. Shuffle 过程本质上都是将 Map 端获得的数据使用分区器进行划分,并将数据发送给对应的 Reducer 的过程

map端的shuffle

  1. input, 根据split输入数据,运行map任务;
  2. partition, 每个map task都有一个内存缓冲区,存储着map的输出结果;
  3. spill, 当缓冲区快满的时候需要将缓冲区的数据以临时文件的方式存放到磁盘;
  4. merge, 当整个map task结束后再对磁盘中这个map task产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task来拉数据。

reduce端的shuffle

  1. Copy过程,拉取数据;
  2. Merge阶段,合并拉取来的小文件
  3. Reducer计算
  4. Output输出计算结果

spark shuffle

  • hash shuffle and sort shuffle
  • hash shuffle
  1. 普通运行机制

    (1)shuffle write :
    将每个task处理的数据按key进行“分区”。所谓“分区”,就是对相同的key执行hash算法,从而将相同key都写入同一个磁盘文件中,而每一个磁盘文件都只属于reduce端的stage的一个task
    (2)shuffle read :
    stage的每一个task就需要将上一个stage的计算结果中的所有相同key,从各个节点上通过网络都拉取到自己所在的节点上,然后进行key的聚合或连接等操作,shuffle read的拉取过程是一边拉取一边进行聚合的
    (3)问题 :
    Shuffle前在磁盘上会产生海量的小文件,建立通信和拉取数据的次数变多,此时会产生大量耗时低效的 IO 操作,可能导致OOM(Out Of Memory)
  2. 合并机制(consolidate)
  • sort shuffle
  1. 普通运行机制

    (1)在该模式下,数据会先写入一个内存数据结构中(默认5M),此时根据不同的shuffle算子,可能选用不同的数据结构。如果是reduceByKey这种聚合类的shuffle算子,那么会选用Map数据结构,一边通过Map进行聚合,一边写入内存;如果是join这种普通的shuffle算子,那么会选用Array数据结构,直接写入内存。接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。
    (2)排序:
    在溢写到磁盘文件之前,会先根据key对内存数据结构中已有的数据进行排序。
    (3)溢写:
    排序过后,会分批将数据写入磁盘文件。默认的batch数量是10000条,也就是说,排序好的数据,会以每批1万条数据的形式分批写入磁盘文件。写入磁盘文件是通过Java的BufferedOutputStream实现的。首先会将数据缓冲在内存中,当内存缓冲满溢之后再一次写入磁盘文件中,这样可以减少磁盘IO次数,提升性能。
    (4)合并(merge):
    一个task将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并,这就是merge过程,此时会将之前所有临时磁盘文件中的数据读取出来,然后依次写入最终的磁盘文件之中。此外,由于一个task就只对应一个磁盘文件,也就意味着该task为Reduce端的stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset。
  2. byPass机制

    (1)条件:
    a. shuffle map task数量小于spark.shuffle.sort.bypassMergeThreshold参数的值
    b. 不是聚合类的shuffle算子

HashShuffle与SortShuffle

在Spark 1.2以前,默认的shuffle计算引擎是HashShuffleManager,因为HashShuffleManager会产生大量的磁盘小文件而性能低下,在Spark 1.2以后的版本中,默认的ShuffleManager改成了SortShuffleManager。SortShuffleManager相较于HashShuffleManager来说,改进在于,每个Task在进行shuffle操作时,虽然也会产生较多的临时磁盘文件,但是最后会将所有的临时文件合并(merge)成一个磁盘文件,因此每个Task就只有一个磁盘文件。在下一个stage的shuffle read task拉取自己的数据时(自然需要索引文件)只要根据索引读取每个磁盘文件中的部分数据即可。