Spark Sort-Based Shuffle详解

本文详细探讨了Spark中Sort-Based Shuffle的必要性、工作原理、优缺点以及其与Hash-based Shuffle的区别。通过Sort-Based Shuffle,Spark能处理大规模数据并在大型集群上高效运行。文章还介绍了Sort-Based Shuffle的实现细节,包括数据分类、数据聚集以及如何减少中间文件的数量。最后,讨论了Sort-Based Shuffle的潜在问题和优化策略,如钨丝计划。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:为什么需要Sort-Based Shuffle?
1, Shuffle一般包含两个阶段任务:
第一部分:产生Shuffle数据的阶段(Map阶段,额外补充,需要实现ShuffleManager中的getWriter来写数据(数据可以通过BlockManager写到Memory,Disk,Tachyon等,例如想非常快的Shuffle,此时可以考虑把数据写在内存中,但是内存不稳定,所以可以考虑增加副本。建议采用MEMONY_AND_DISK方式);
第二部分:使用Shuffle数据的阶段(Reduce阶段,额外补充,Shuffle读数据:需要实现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;
二:Hash-based Shuffle
1, Spark Shuffle在最开始的时候只支持Hash-based Shuffle:默认Mapper阶段会为Reducer阶段的每一个Task单独创建一个文件来保存该Task中要使用的数据。
优点:就是操作数据简单。
缺点:但是在一些情况下(例如数据量非常大的情况)会造成大量文件(M*R,其中M代表Mapper中的所有的并行任务数量,R代表Reducer中所有的并行任务数据)大数据的随机磁盘I/O操作且会形成大量的Memory(极易造成OOM)。
2,Hash-based Shuffle产生的问题:
第一:不能够处理大规模的数据
第二:Spark不能够运行在大规模的分布式集群上!
3,Consolidate机制:
后来的改善是加入了Consolidate机制来将Shuffle时候产生的文件数量减少到C*R个(C代表在Mapper端,同时能够使用的cores数量,R代表Reducer中所有的并行任务数量)。但是此时如果Reducer端的并行数据分片过多的话则C*R可能已经过大,此时依旧没有逃脱文件打开过多的厄运!!!Consolidate并没有降低并行度,只是降低了临时文件的数量,此时Mapper端的内存消耗就会变少,所以OOM也就会降低,另外一方面磁盘的性能也会变得更好。
Spark在引入Sort-Based Shuffle之前,适合中小型数据规模的大数据处理!
三:Sort-Based Shuffle
1, 为了让Spark在更大规模的集群上更高性能处理更大规模的数据,于是就引入了Sort-based Shuffle!从此以后(Spark1.1版本开始),Spark可以胜任任何规模(包括PB级别及PB以上的级别)的大数据的处理,尤其是钨丝计划的引入和优化,Spark更快速的在更大规模的集群处理更海量的数据的能力推向了一个新的巅峰!
2, 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实现;
3,Spark1.6默认采用的就是Sort-based Shuffle的方式:

val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")

上述源码说明,你可以在Spark配置文件中配置Spark框架运行时要使用的具体的ShuffleManager的实现。可以在conf/spark-default.conf加入如下内容:
spark.shuffle.manager SORT 配置Shuffle方式是SORT
4, Sort-based Shuffle的工作方式如下:Shuffle的目的就是:数据分类,然后数据聚集。
这里写图片描述
1) 首先每个Shuf

### Spark Shuffle机制详解 #### SortShuffle机制概述 SortShuffleSpark中的一种重要shuffle实现方式,在内存数据结构(默认大小为5MB)内完成排序操作。此过程中可能会产生多个磁盘小文件,具体数目取决于配置和数据量[^1]。 对于特定条件下,SortShuffle可以启用一种称为bypass的优化路径。当满足以下两个条件之一时,则会激活这种高效模式: - shuffle map tasks的数量少于`spark.shuffle.sort.bypassMergeThreshold`设定阈值,默认情况下这个数值被设为200; - 使用的是不涉及预聚合运算的shuffle算子实例,例如`reduceByKey`这样的操作符[^3]。 在这种特殊处理流程下,系统不再执行任何排序活动,从而显著提升了整体效率并减少了资源消耗。 #### Tungsten-Sort Based Shuffle集成 自版本1.6.0起,无论是传统的Sort Shuffle还是基于Tungsten框架改进后的新型sort-based方法都被整合进了统一的SortShuffle体系之中。这意味着每当遇到合适的场景——即符合更先进的Tungsten-sort based shuffle适用标准的情况下,Spark将会优先选用后者;反之则沿用经典的Sort Shuffle逻辑来进行任务调度与数据交换工作[^2]。 值得注意的是,在后续发布的2.x系列里边,官方已经彻底淘汰了hash-based shuffle方案,使得当前主流版本仅保留有上述提到过的sort-oriented策略作为唯一的选择。 #### HashShuffle的历史背景及其局限性 早期版本曾广泛使用的HashShuffle由于存在一些固有问题,如生成大量临时文件以及较高的writer端缓冲区占用率等现象,促使开发团队寻求更加有效的替代品。因此引入了一套借鉴Hadoop MapReduce设计理念的新颖架构来改善这些问题[^4]。 #### Executor角色说明 在整个shuffle阶段,实际的数据写入动作是由各个executor节点负责协调完成的。这些worker进程不仅承担着各自分区内的计算职责,同时也需确保产生的中间结果能够按照既定规则正确无误地传递给下游stage的任务去进一步加工处理。每个parent RDD所对应的child RDD都会对应创建相应数量的小文件用于存储传输所需的信息片段[^5]。 ```python # Python伪代码展示如何设置相关参数以利用bypass特性 conf = spark.conf.set("spark.shuffle.sort.bypassMergeThreshold", "200") rdd = sc.parallelize([i for i in range(100)]).map(lambda x: (x % 10, x)) result = rdd.reduceByKey(lambda a,b:a+b) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值