Spark学习(五)Spark Shuffle及内存分配

本文深入解析Spark中的Shuffle机制,包括HashShuffle和SortShuffle的运行原理,探讨Shuffle过程中磁盘小文件寻址问题及可能遇到的挑战。同时,文章提供了Executor内存管理策略和Shuffle调优技巧,帮助读者理解并优化Spark作业。

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

一、什么是Spark Shuffle?

1、Shuffle中文意思就是“洗牌”,在Spark中Shuffle的目的是为了保证每一个key所对应的value都会汇聚到同一个节点上去处理和聚合。
2、在Spark中,什么情况下会发生shuffle?
reduceByKey、groupByKey、sortByKey、countByKey、join等操作。

3、Spark中的Shuffle包括两种:

  1. HashShuffle
  2. SortShuffle

二、HashShuffle运行原理

SortShuffle的运行机制也分成两种:

  1. 普通运行机制
  2. 合并机制

普通运行机制:
Spark Shuffle图解
Shuffle Write阶段:

由于Stage后面紧跟了另一个Stage,所以数据落地会发生在Shuffle Write阶段。为了将分区中数据相同的key写入一个分区文件中,需要将task计算结果的key的hashcode值与Reduce task个数取模,从而确定将结果写入哪个分区文件中,这样即可保证相同的key在一个分区文件中。为了加快向磁盘写文件的速度,需要事先设置一个buffer作为缓存,每个buffer的大小是32K。

Shuffle Red阶段:

Reduce task从上个Stage的task节点中拉取属于自己的分区文件,这样即可保证每一个Key所对应的Value都会在同一个节点上。拉取的过程属于现拉现用

合并机制:
倘若Executor只有一个core,所以每次只能有一个task执行,当第一个task执行完成后,第二个task会复用第一个task所创建的buffer磁盘文件,从而减少磁盘文件的个数。
合并前:
合并机制执行前磁盘小文件数为12
合并后:
合并机制执行前磁盘小文件数为6

三、SortShuffle运行原理

SortShuffle的运行机制也分成两种:

  1. 普通运行机制
  2. bypass运行机制

普通运行机制:
在这里插入图片描述
由于Spark只是一个计算框架,没有办法严格控制Executor内存,只能采取监控的方式去监控内存的情况,内存数据初始值的大小大约默认为5M,当超出5M的时候,例如5.02M,监控内存数据的对象就会再去申请5.02*2-5=5.04M内存,如果申请到内存就不必进行溢写,否则再进行溢写。

Shuffle Write阶段:
溢写到磁盘的过程与MapReduce的ShuffleWrite阶段一样。
区别:

  1. 内存数据初始值是5M大小,它可以申请扩大,而MapReduce中的Buffer是固定的100M。
  2. 溢写除了生成磁盘文件,还有索引文件,索引文件是对磁盘文件的描述,还有记录每个分区的起始位置以及终止位置。

Shuffle Red阶段:
Reduce Task首先会解读索引文件,然后拉取相应分区的数据,然后再处理。

bypass运行机制:
在这里插入图片描述
bypass运行机制与普通运行机制相比,缺少了忘内存数据存放、排序。除此之外,其余流程一样。
bypass运行机制的触发条件:
shuffle reduce task数量小于spark.shuffle.sort.bypassMergeThreshold参数的值。

四、Shuffle过程中,磁盘小文件寻址问题

在这里插入图片描述
1、Map task执行完毕后,将自己的执行结果信息(比如:磁盘小文件的位置、最终执行状态信息)封装到mapstatus中,然后调用本进程中的MapOutputTrackerWorker,将mapstatus对象发送给Driver中的MapOutputTrackerWorker。
2、Reduce task会调用自己进程中的MapOutputTrackerWorker对象去向MapOutputTrackerWorker获取磁盘小文件的位置信息,然后将位置信息给BlockManagerSlave去拉取磁盘小文件。(默认会启动5个子线程去拉取数据,但5个子线程总共拉取的数据量不能超过64M)。拉来的数据会存在shuffle聚合内存中(20%x80%),以供Reduce task计算。

注:
Reduce task中的计算模式也是pipeline管道计算模式。

五、Shuffle可能面临的问题

由HashShuffle的流程图可知:磁盘小文件(分区文件)的个数=m(map task num)*r(reduce task num)
当磁盘小文件过多时,带来的问题有:

  1. write阶段会创建大量写文件的对象
  2. read阶段拉取数据需要进行多次网络传输
  3. read阶段会创建大量读文件的对象
  4. 读写对象过多造成JVM内存不足,从而导致内存溢出

六、Executor的内存管理

Excutor内存管理方式有两种:

  1. 静态的内存管理
  2. 统一的内存管理

静态的内存管理:
在这里插入图片描述
unroll:用来进行反序列化。
两块防止OOM的内存,可以供JVM使用

统一的内存管理:
在这里插入图片描述
统一内存管理中,75%中的两块内存可以互相借用,但是有最大限度。

七、Shuffle调优

spark.shuffle.file.buffer
默认值:32k
参数说明:该参数用于设置shuffle write task的BufferedOutputStream的buffer缓冲大小。将数据写到磁盘文件之前,会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。
调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。

spark.reducer.maxSizeInFlight
默认值:48M

参数说明:该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。
调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如96m),从而减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。

spark.shuffle.io.maxRetries
默认值:3

参数说明:shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,是会自动进行重试的。该参数就代表了可以重试的最大次数。如果在指定次数之内拉取还是没有成功,就可能会导致作业执行失败。
调优建议:对于那些包含了特别耗时的shuffle操作的作业,建议增加重试最大次数(比如60次),以避免由于JVM的full gc或者网络不稳定等因素导致的数据拉取失败。在实践中发现,对于针对超大数据量(数十亿~上百亿)的shuffle过程,调节该参数可以大幅度提升稳定性。
shuffle file not find taskScheduler不负责重试task,由DAGScheduler负责重试stage

spark.shuffle.io.retryWait
默认值:5s

参数说明:具体解释同上,该参数代表了每次重试拉取数据的等待间隔,默认是5s。
调优建议:建议加大间隔时长(比如60s),以增加shuffle操作的稳定性。

spark.shuffle.memoryFraction
默认值:0.2

参数说明:该参数代表了Executor内存中,分配给shuffle read task进行聚合操作的内存比例,默认是20%。
调优建议:在资源参数调优中讲解过这个参数。如果内存充足,而且很少使用持久化操作,建议调高这个比例,给shuffle read的聚合操作更多内存,以避免由于内存不足导致聚合过程中频繁读写磁盘。在实践中发现,合理调节该参数可以将性能提升10%左右。

spark.shuffle.manager
默认值:sort

参数说明:该参数用于设置ShuffleManager的类型。Spark 1.5以后,有三个可选项:hash、sort和tungsten-sort。HashShuffleManager是Spark 1.2以前的默认选项,但是Spark 1.2以及之后的版本默认都是SortShuffleManager了。tungsten-sort与sort类似,但是使用了tungsten计划中的堆外内存管理机制,内存使用效率更高。
调优建议:由于SortShuffleManager默认会对数据进行排序,因此如果你的业务逻辑中需要该排序机制的话,则使用默认的SortShuffleManager就可以;而如果你的业务逻辑不需要对数据进行排序,那么建议参考后面的几个参数调优,通过bypass机制或优化的HashShuffleManager来避免排序操作,同时提供较好的磁盘读写性能。这里要注意的是,tungsten-sort要慎用,因为之前发现了一些相应的bug。

spark.shuffle.sort.bypassMergeThreshold
默认值:200

参数说明:当ShuffleManager为SortShuffleManager时,如果shuffle read task的数量小于这个阈值(默认是200),则shuffle write过程中不会进行排序操作,而是直接按照未经优化的HashShuffleManager的方式去写数据,但是最后会将每个task产生的所有临时磁盘文件都合并成一个文件,并会创建单独的索引文件。
调优建议:当你使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大一些,大于shuffle read task的数量。那么此时就会自动启用bypass机制,map-side就不会进行排序了,减少了排序的性能开销。但是这种方式下,依然会产生大量的磁盘文件,因此shuffle write性能有待提高。

如果你的Application在执行的过程中,出现了类似reduce OOM的错误,错误原因会有哪一些?
三种解决方案:
1、提高Executor的内存
2、提高shuffle聚合的内存比例
3、减少每次拉取的数据量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值