Spark Sort-Based Shuffle学习笔记

一、为什么需要Sort-Based Shuffle?
1. Shuffle一般包含两阶段的任务:第一部分,即产生Shuffle数据的阶段(Map阶段,需要实现ShuffleManager中的getWriter方法来写数据(数据通过BlockManager可以写入Memory、Disk、Tachyon等,例如想实现非常快的Shuffle,就可以把数据写入内存中,但是内存不稳定,建议采用MEMORY_AND_DISK方式));第二部分,即使用Shuffle数据的阶段(Reduce阶段,需要实现ShuffleManager中的getReader方法来获取数据,Reader会向Driver去获取上一个Stage产生的Shuffle数据)。
2. Spark的Job会被划分为很多Stage。
如果只有一个Stage,则这个Job相当于只有一个Mapper阶段,不会产生Shuffle,适用于简单的ETL(数据获取);
如果有多个Stage,则最后一个Stage就是最终的Reducer,最左侧的Stage仅仅是整个Job的Mapper,中间任意一个Stage是其父Stage的Reducer,且是其子Stage的Mapper。
3. Spark Shuffle在最开始的时候只支持Hash-Based Shuffle,Hash-Based Shuffle默认Mapper阶段的每个Task会为Reducer阶段的每个Task单独创建一个文件来保存该Task中要使用的数据,但是在一些情况下(数据量非常大)会造成大量文件(M*R,*其中M代表Mapper中所有的并行任务数量,R代表Reducer中所有的并行任务数量)的随机磁盘IO操作,且会形成大量的Memory消耗,极易造成OOM,这是致命的问题。因为第一无法处理大规模的数据,第二Spark不能运行在大规模的分布式集群上。后来的改善方案是加入了Shuffle Consolidate机制来将Shuffle时产生的文件数量减少到*C*R个(C代表在Mapper断同时能够使用的Cores的数量,R代表Reducer中所有的并行任务数量),但是此时如果Reducer端的并行任务过多,则C*R可能依旧很大,仍然无法逃脱文件打开过多的厄运。
Spark在引入Sort-Based Shuffle之前(Spark1.1版本前),比较适用于中小规模的大数据处理。
4. 为了让Spark在更大规模的集群上更高性能地处理更大规模的数据,引入了Sort-Based Shuffle,从此Spark可以胜任任意规模(包含PB级别及PB以上的级别)的大数据处理,尤其是随着钨丝计划的引入和优化,把Spark更快速的在更大规模的集群处理更海量数据的能力推向了巅峰。
5. Spark1.6版本支持至少三种类型的Shuffle:

    // Let the user specify short names for shuffle managers
    val shortShuffleMgrNames = Map(
      "hash" -> "org.apache.spark.shuffle.hash.HashShuffleManager",
      "sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager",
      "tungsten-sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager")
    val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")
    val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName)
    val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)

实现ShuffleManager接口可以根据自己的业务需要最优化的使用自定义的Shuffle实现。
6.Spark1.6默认采用Sort-Based Shuffle的方式:
val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")
上述源码说明,我们可以在Spark的配置文件中配置Spark框架运行时要使用的具体的ShuffleManager的实现。
也可以修改spark-default.conf文件,加入如下内容:
spark.shuffle.manager SORT
Sort-Based Shuffle不会为Reducer中的每个Task生产一个单独的文件,相反,Sort-Based Shuffle会把Mapper中每个ShuffleMapTask的所有输出数据Data分别只写到一个文件中,因为每个ShuffleMapTask中的数据会被分类,所以Sort-Based Shuffle使用了index文件存储具体ShuffleMapTask输出数据在同一个Data文件中是如何分类的信息。所以Sort-Based Shuffle会在Mapper中的每个ShuffleMapTask中产生两个文件:Data文件和Index文件。其中Data文件存储当前Task的Shuffle输出,Index文件存储Data文件中的数据通过Partitioner的分类信息,下一个Stage中的Task则根据Index文件中的索引信息来获取自己需要的上一个Stage中的ShuffleMapTask产生的数据。
Sort-Based Shuffle会产生2*M(M代表Mapper中并行的Partition的总数量,也就是总的ShuffleM的数量)个Shuffle临时文件。
由此,Shuffle产生的临时文件的数量依次为:
Basic Hash Shuffle:M*R
Consolidate方式的Hash Shuffle:C*R
Sort-Based Shuffle:2*M

在Sort-Based Shuffle中Reducer是如何获取需要的数据的?
具体而言,Reducer首先找Driver去获取父Stage中每个ShuffleMapTask输出的位置信息,根据位置信息获取Index文件,解析Index文件,从解析的Index文件中获取Data文件属于自己的那部分数据内容。

二、默认Sort-Based Shuffle的几个缺陷:
1. 如果Mapper中Task的数量过大,依旧会产生很多小文件,此时在Shuffle传递数据到Reducer的过程中,Reduce会需要同时打开大量的记录来进行反序列化,导致大量的内存消耗和GC的巨大负担,造成系统缓慢甚至崩溃。
2. 如果需要在分片内也进行排序,此时要进行Mapper端和Reducer端的两次排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值