day25:Spark Sort-Based Shuffle内幕工作机制、案例实战、源码剖析、优缺点及改进方式

以下博客整理来源于DT大数据梦工厂:
一:为什么需要Sort-Based shuffle
1、shuffle 一般包含2个阶段任务:第一部分,产生Shuffle数据的阶段(Map阶段,需要实现ShuffleManager 中的getWriter来写数据,可以通过blockManager将数据写入、Memory,Disk,Tachyon都可以,也可以写副本(例如想非常快的shuffle此时可以考虑吧数据写在Memory中,但是内存不稳定可以用副本的方式如果发现这台机器不行切换到另一台上。企业使用中都是使用MEMORY_AND_DISK :内存使用不足放在Disk));第二部分,使用shuffle数据阶段(Reduce阶段,需要实现ShuffleManager中的getReader,reader 会向Driver 获取上一个Stage产生的Shuffle数据)
2、spark job会被划分成很多stage
如果只有一个Stage,则最后一个Stage就是最终的reducer,最左侧的第一个Stage就仅仅是整个Job的Mapper,中间所有的任意一个Stage是其父Stage的reducer且是其子stage的Mapper;
3、Spark shuffle 在最开始的时候只支持Hash-based shuffle 默认mapper阶段会为Reducer阶段的每一个Task单独创建一个文件来保存该Task中要使用的数据,但是在一些情况下(例如数据量非常大的情况)会造成大量文件(M*R,其中M代表Mapper中的所有并行任务数量,R代表Reducer中所有的并行任务数量)的随机IO磁盘操作且会性能大量的Memory消息极易造成OOM,这是致命的问题。因为第一不能处理大规模的数据;第二spark不能运行在大规模的分布式集群上!后来的改善方式是加入了Shuffle Consolidate 机制来讲shuffle 时候产生的文件减少到C×R个(C代表Mapper端同时能够使用的cores数量,R代表Reducer由所有的并行任务数量),但是此时如果redcer端的并行数据分片过多的话则C*R可能已经过大,此时依旧没有逃过文件打开过多的厄运!
4、为了让spark 在更大规模集群上更高性能处理更大规模的数据,于是引入了Sort-based-shuffle(1.0.0版本引进),从此以后(1.1以后)spark 可以胜任任意规模(包含PB和PB级别以上数据)的大数据处理,尤其是钨丝计划的引进和优化,把spark更快速的在更大集规模集群的处理更海量的数据的能力推上新的巅峰。
5、spark1.6 版本技术支持至少三种shuffle(还可以自定义)。
 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
hadoop Mapshuffle是环形内存缓冲区(有数据又有索引)把数据输出出去
6、saprk1.6默认采用的就是sort-base shuffle 的方式:
 val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")
    val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName)
    val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)
通过修改配置文件方式:
 修改 conf/spark-default.conf 加入如下配置文件: spark.shuffle.,manager.SORT
sort-base shuffle不会为每个reducer中的Task 单独生成一个文件,,相反sort-based shuffle 会把Mapper中每个shuffleMapTask所有的输出Data只写到一个文件中。因为每个shuffleMapTask中的数据会被分类,所以sort-based shuffle 使用了Index文件存储具体shuffleMapTask输出数据在同一个Data文件中是如何分类的信息!!!所以说基于sort-base 的shuffle 会在Mapper中的每一个shuffleMapTask中产生两个文件:Data文件和Index文件,其中Data存储当前Task的shuffle输出的, 而index文件则存储数据了Data文件中的数据通过Partition的分类信息,此时下一阶段的Stage中年的Task就是根据这个Index文件获得自己所要抓取的上一个Stage中的shuffleMapTask产生的数据的
排序的shuffle会有多少个文件产生
Sort-based shuffle 会产生2M(M代表Maper阶段中并行的Partition的总数量,其实就是mapper端ShuffleMapTask的总数量)个shuffle临时文件
回顾整个shuffle的历史,shuffle产生的临时文件数量变化依次为:
 basic Hash Shuffle: M×R
Consalidate方式的 Hash Shuffle: C*R
sort-based shuffle :2M

二: 在集群中动手实践sort-based Shuffle
代码:
在sort-based shuffle 中的reducer是如何获得自己需要的数据呢?
具体而言reducer首先找Driver去获取父Stage中每个shuffleMapTask输出的位置信息,根据位置信息获取Index文件,解析index文件从解析的index文件中获取Data文件中属于自己的那部分内容。
三、 默认Sort-base Shuffle 的几个缺陷
1、如果Mapper端中Task的数量过大,依旧会产生很多小文件,此时shuffle 传递数据的过程到reducer端,reducer会需要同时大量的记录来进行反序化导致大量的内存消耗和GC的巨大负担,造成系统缓慢甚至者瘫痪。
2、如果需要在分片内页需要排序的话此时也需要进行Mapper 和reducer端的两次排序。


一旦父stage编写完后,后面的子stage就可以一边写一边获得数据。
源码类:
MapPartitonsRDD---SparkEvn--shuffleManager

DT大数据梦工厂联系方式:
新浪微博:www.weibo.com/ilovepains/
微信公众号:DT_Spark
博客:http://.blog.sina.com.cn/ilovepains
TEL:18610086859
Email:[email protected]

你可能感兴趣的:(day25:Spark Sort-Based Shuffle内幕工作机制、案例实战、源码剖析、优缺点及改进方式)