Spark之【Shuffle】

本文探讨了Hadoop中Shuffle在大数据处理中的重要性,尤其在Hadoop的排序过程和Spark中的性能消耗。文章详细介绍了Shuffle的三次排序,以及如何通过优化如HashShuffle、Consolidate机制和SortShuffle来提升性能。此外,还涉及了Bypass机制和Push-BasedShuffle的原理和适用场景。
摘要由CSDN通过智能技术生成

Shuffle是大数据中的性能杀手,其来源于大数据中的元老级组件Hadoop。

在Hadoop中,map被定义为数据的初次拆分获取解析阶段,reduce被定义为负责最终数据的收集汇总阶段,除了业务逻辑的功能外,其他的核心数据处理都是由shuffle来支持。

Hadoop中Shuffle的三次排序

  1. map端内存中的快速排序。shuffle的map端会在内存中开辟了一个缓冲区,当K-V数据从map出来后,分批进入缓冲区,对他们按K进行排序,并且按照map的逻辑进行分区,在出缓冲区落盘的时候,完成排序。

  2. map端分区文件的归并排序。一旦内存中缓存区满了,就会被Hadoop写到file中,这个过程叫Spill,所写的文件叫做spill File(这些spill File存在map所在的host的local disk上,而不是HDFS)。当Map结束时,这些spill file会被merge起来,按照分区进行归并排序合并为多个文件。

  3. reduce端文件归并排序。Reducer内部有一个thread负责定期询问map output的位置。另一个thread会把拷贝过来的map output file merge成更大的file。当一个reduce task所有的map output都被拷贝到一个他的jost上时,reduce就要开始对他们排序了。  

Spark Shuffle

大多数Spark作业的性能主要就是消耗了Shuffle过程,因为该环节包含了大量饿磁盘IO、序列化、网络数据传输等操作。因此,如果要让作业的性能更上一层楼,就有必要对shuffle过程进行调优。影响一个Spark作业性能的因素主要还是代码开发、资源参数以及数据倾斜,shuffle调优只是整个Spark的性能调优中占到一小部分而已。

Stage划分

在DAG调度过程中,Stage阶段的划分是根据是否有shuffle过程,也就是存在ShuffleDependency款依赖的时候,需要进行shuffle,这时候要将作业job划分成过个stage;Spark划分Stage的整体思路是:从后往前推,遇到款依赖就断开,划分为一个stage;遇到窄依赖就将这个RDD加入到该Stage中。

Task的类型两种:ShuffleMapTask和ResultTask

简单的说,DAG的最后一个阶段会为每个结果的partition生成一个ResultTask,即每个Stage里面的Task的数量是由该Stage中最后的一个RDD的Partition的数量所决定的,而其余所有阶段都会生车过ShuffleMapTask;之所以称之为shuffleMapTask是因为它需要将自己的计算结果通过shuffle到下一个stage中。

  • Hash Shuffle:顾名思义,就是采取Hash的方式在Map的任务中为每个reduce端的任务生成一个文件。因为如果有M个Map任务,R个reduce任务就会产生M*R个文件。巨量磁盘小文件而产生大量性能低下的IO操作,从而性能较低,因为其巨量的磁盘小文件还可能导致OOM,HashShuffle的合并机制通过重复利用buffer从而将磁盘小文件的数量降低到了Core R个,但是当Reducer端的并行任务或者数据分片过多的时候,依然会产生大量的磁盘小文件。

    • 优化后的HashShuffle:开启consolidate机制后,在shuffle write过程中,task就不是为了下游stage的每个task创建一个磁盘文件了。此时会出现shuffleFileGroup的概念,每个shuffleFileGroup会对应一批磁盘文件,磁盘文件的数量与下游stage的task数量时相同的。一个Executor上有多少个CPU core,就可以并行执行多少个task。而第一批并行执行的每个task都会创建一个shuffleFileGroup,并将数据写入对应的磁盘文件内。

      Executor 的CPU core执行完一批task,接着执行下一批task时,下一批task就会复用之前已有的shuffleFileGroup,包括其中的磁盘文件。也就是说,此时task会将数据写入已有的磁盘文件中,而不会写入新的磁盘文件中。因此,consolidate机制允许不同task复用同一批磁盘文件,这样就可以有效将多个task的磁盘文件进行一定程度上的合并,从而大幅度减少磁盘文件的数量,进而提升shuffle write的性能。

      未经优化:
      上游的task数量:m
      下游的task数量:n
      上游的executor数量:k  (m>=k)
      总共的磁盘文件:m*n

      优化之后的:
      上游的task数量:m
      下游的task数量:n
      上游的executor数量:k  (m>=k)
      总共的磁盘文件:k*n
       

  • Sort Shuffle :首先,在Shuffle的map阶段会将所有数据进行排序,并将分区的数据写入同一个文件中,在创建数据文件的同时会产生索引文件,来记录分区的大小和偏移量。所以这里产生的数量和reduce分区就没有关系了,只会产生2M个临时文件。

    • 我们知道在Spark的DAG中,顶点是一个个RDD,边则是RDD之间通过dependencies属性构建成的父子关系。dependencies又分为宽依赖和窄依赖,分别对应ShuffleDependency和NarrowDependency。当RDD间的依赖关系为ShuffleDependency时,RDD会通过其SparkEnv向ShuffleManager注册一个shuffle,并返回当前处理shuffle所需要的句柄;

  • ByPass机制:此时task会为下游task都创建一个临时磁盘文件,并将数据按照key进行hash然后根据key的hask值,将key写入对应的磁盘文件中。当然,写入磁盘文件时也是先写入内存缓冲区,缓冲写满之后再溢写到磁盘文件。最后,同样的将所有的临时文件都合并成一个磁盘文件,并创建一个单独的索引文件。

    1. bypass机制与普通的SortShuffleManager运行机制的不同:

      1、磁盘写机制不同;

      2、不会进行排序

      触发bypass机制的条件:

      shuffle map task的数量小于spark.sort.bypassMergeThreshold参数的值(默认200)

  • Push-Based Shuffle:push-based shuffle 方案,会在Mapper执行后并且会被自动合并数据,然后将数据移动到下游的reducer。目前只支持Yarn的实现。

    • push-based shuffle 利用共享的ESS服务,在map阶段时将溢写的数据文件,通过推送的方式推送到reduce对应的ESS节点,并在其中对小文件进行合并。其中push-based shuffle 实现了一个magnet shuffle服务,是一个增强的Spark ESS,它可以接受远程推送的shuffle block,它会将block合并到每一个唯一shuffle分区文件。

      push merge shuffle采用的push-merge shuffle机制。Mapper生成的shuffle数据被推送到远程的magnet shuffle服务,并按照每个shuffle合并。Magnet在此期间可以将小的shuffle块的随机读取转换为MB大小的顺序读取。这个push操作与map任务完全解耦,所以无需添加到执行map任务的运行时中,一旦推送失败就会导致maptask失败。

      尽可能地执行push,Magnet无需所有的shuffle都是完美的push成功。通过push-merge shuffle,Magnet复制shuffle数据,Reducer可以获取合并后的、或者是没有合并的shuffle数据作为任务输入。也就是,即使没有合并也可以读取。

  • 33
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据松松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值