spark的shuffle过程

上一篇写了shuffle的几种机制, 这一篇就介绍一下shuffle拉去数据的过程和executor的内存管理
1、map task处理完数据溢写到本地磁盘后,会将数据结果和落地磁盘文件的位置封装成MapStatus对象中,通过MapoutputTrackerWorker会向Driver端的MapoutputTrackerMaster,Driver端就掌握了磁盘小文件的位置。
2、reduce task拉去数据,会向本地的MapOutputTrackerWork要数据,还会向Driver中的MapoutputTrakerMaster要磁盘小文件的位置,MapOutputTrackerMaster返回磁盘小文件的位置(MapStatus)

3、获取小文件的位置后,BlockManagerWork会通过ConnectionManager连接磁盘小文件所在的BlockManagerWork

4、连接上后会开启线程拉去磁盘小文件,放在executor中的内存中, BlockTransferService默认启动5个子线程拉去数据,默认这个线程一次拉去的数据不能超过48M

5、BlockManagerMaster向BlockManagerWord通信是在比如说cache,还有广播变量时,cache在Driver端,通过两者进行通信cache

reduce端拉去的数据存储在executor的shuffle.memory中(占executor的内存的0.2), reduce端拉去数据时默认一次最多拉去的数据时48M,如果shuffle.memory是50M ,第一次拉去数据是48M 剩余2M,第二次拉去是30M, 不会出现内存溢出,会溢写磁盘。 但是如果shuffle.memory的内存是30M,第一次拉去48M,那么就会出现OOM内存溢出, 只要第一拉去不会内存溢出,以后都不会出现内存溢出

在这里插入图片描述

内存管理
Spark内存管理
spark在1.6之前使用的静态内存管理,spark1.6之后使用的是同一内存管理, spark1.6使用的就是同一内存管理,默认的spark.memory.uselegacy.Mode 是false(同一内存管理)。
executor的静态内存管理,分成3大部分,
第一部分是0.2给task运行,
第二部分占0.2,这0.2里有分为0.8和0.2, 0.2是预留内存,0.8是shuffle聚合内存
第三部分占0.6,这0.6中有划分为2部分,0.1是预留内存,0.9是再划分为两部分,一部分是反序列化用的,一部分是RDD的缓存和广播变量使用
executor的统一内存管理
统一内存管理相较静态内存管理来说比较简单,
第一部分 ,executor的内存有300M是预留内存
第二部分,(总的内存-300M) 的0.25是task运行使用
第三部分,(总的内存-300M)的0.75, 这0.75又划分为俩部分,0.5是给shuffle聚合内存,0.5是RDD的缓存和广播变量,但是这俩部分的内存可以相互借用,当shuffle聚合内存不够用时可以借rdd缓存的内存
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SparkShuffle过程是指在数据处理过程中,将数据重新分区和排序的过程。它是Spark中非常重要的一个操作,用于将数据从一个RDD的分区传输到另一个RDD的分区。 SparkShuffle过程包括两个阶段:Map阶段和Reduce阶段。 在Map阶段,每个Executor上的任务(Task)会将输入数据根据指定的分区函数进行分区,并将分区后的数据写入磁盘上的.data文件中。同时,还会生成一个.index文件,用于记录每个分区的数据在.data文件中的位置信息。 在Reduce阶段,Spark会根据分区函数将数据重新分配到不同的Executor上的任务中。每个任务会读取自己负责的分区数据,并进行合并、排序等操作,最终生成最终结果。 SparkShuffle过程可以使用不同的策略来实现,其中包括BypassMergeSortShuffleWriter、SortShuffleWriter和UnsafeSortShuffleWriter等。 BypassMergeSortShuffleWriter是一种优化策略,它会尽量减少数据的复制和排序操作,提高Shuffle的性能。 SortShuffleWriter是一种常用的策略,它会将数据写入磁盘,并使用外部排序算法对数据进行排序。 UnsafeSortShuffleWriter是一种更高效的策略,它使用了内存进行排序,减少了磁盘IO的开销。 下面是一个示例代码,演示了SparkShuffle过程: ```scala val inputRDD = sc.parallelize(List(("apple", 1), ("banana", 2), ("apple", 3), ("banana", 4))) val shuffledRDD = inputRDD.groupByKey() val resultRDD = shuffledRDD.mapValues(_.sum()) resultRDD.collect().foreach(println) ``` 这段代码首先创建了一个输入RDD,其中包含了一些键值对数据。然后使用groupByKey()函数对数据进行分组,生成一个ShuffledRDD。最后使用mapValues()函数对每个分组进行求和操作,得到最终结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值