shuffle过程

案例

假设我们写一个wordcount的程序:

sc.
textFile("hdfs://hadoop102:8020/spark-input/word.txt")
.flatMap(_.split(" "))
.map((_,1))
.reduceByKey(_+_)
.saveAsTextFile("hdfs://hadoop102:8020/spark-out/wcout")

观看job:

在这里插入图片描述

划分了两个stage,因为出现了shuffle:

在这里插入图片描述
一共是4个task,第一个stage两个task,第二个stage两个task。

shuffle write溢写了171.0 B数据到本地磁盘。shuffle read读取这171.0 B的数据。

/tmp目录下,我们发现了溢写的内容:

在这里插入图片描述
在这里插入图片描述
一个data文件,一个index文件。

所以,他是如何工作的?

shuffle write准备

在这里插入图片描述
我们从executor注册开始讲起。

在这里插入图片描述

new Executor的时候会准备一个线程池。

在这里插入图片描述
driver将task发来之后,executor就要准备执行了。

在这里插入图片描述
他new了一个TaskRunner然后丢到executor的线程池中执行,所以我们要看TaskRunnerrun方法。

在这里插入图片描述
他拿到一个序列化器将task反序列化出来。

在这里插入图片描述

然后进入task.run

在这里插入图片描述
task是spark的最小执行单元。

task有两种:ShuffleMapTaskResultTask,对应的stage分别是ShuffleMapStageResultStage

ResultTask是直接产生结果的task,而ShuffleMapTask可以从源头读数据,可以从上一个stage中溢写到磁盘的溢写文件中读数据。

在我们的wordcount案例中,textFileflatMapMap属于ShuffleMapStagereduceByKeysaveAsTextFile属于ResultStage

在这里插入图片描述
所以在runTask(context)这个抽象方法中,我们先走ShuffleMapTaskrunTask方法:

在这里插入图片描述
这里,他先拿到最后一个rdd,然后拿到rdd的依赖。然后往外写。

在这里插入图片描述
写之前,他要拿最后一个rdd的iterator。

在这里插入图片描述
他问我们有没有cachepersist,或者做checkpoint,显然我们没有,所以进入compute方法:

在这里插入图片描述
这是个抽象方法。因为我们stage0的最后一个rdd是MapPartitionsRDD,所以看这个类的compute方法:

在这里插入图片描述
但是他还要往上找iterator。

一直往上找,直到

在这里插入图片描述
HadoopRDD这里就要从数据源读数据了。

在这里插入图片描述
并且他返回的也是一个迭代器。

既然数据都读来了,然后就从前往后flatMapMap应用函数计算。

shuffle write、read

在这里插入图片描述
既然要shuffle write,我们要先拿到writer。

在这里插入图片描述

getWriter也是抽象的,幸运的是ShuffleManager只有一个实现:SortShuffleManager

在这里插入图片描述

而这个SortShuffleManager是在初始化spark环境时创建的。

在这里插入图片描述
使用哪一种shuffle writer,需要一个handle的模式匹配,而这个handle是传进来的:

在这里插入图片描述

在这里我们能知道返回哪一个ShuffleHandle

在这里插入图片描述
首先看是否使用BypassMergeSortShuffleHandle

mapSideCombine直接不行。

因为reduceByKey调用的是combineByKeyWithClassTag

在这里插入图片描述

它的mapSideCombine默认是true

我们debug一下:

在这里插入图片描述

首先可以看到它的血缘关系。

在这里插入图片描述
然后mapSideCombine也确实为true

所以不使用BypassMergeSortShuffleHandle

至于是否用SerializedShuffleHandle,我们接着看:

在这里插入图片描述
他首先问我们的序列化器是不是支持重排序的。

java的序列化器是不支持的,kyro是支持的。

在这里插入图片描述
我们用的是kyro,所以看下一个条件:

在这里插入图片描述
又是问有没有mapSideCombine,我们的为true,所以直接跳过这个handle。

在这里插入图片描述

所以最后返回的就是BaseShuffleHandle

在这里插入图片描述
那么我们用的writer就是SortShuffleWriter

在这里插入图片描述
进入insertAll

在这里插入图片描述
现在就要执行map端的聚合了,将定义的对第一个数的操作逻辑和分区内的操作逻辑取出来应用:

在这里插入图片描述

在这里插入图片描述
注意到此时才会用分区器的getPartition方法。

在这里插入图片描述
最后得到的结果就是分区号加上区内聚合的结果。

在这里插入图片描述
最后有一个写入磁盘的操作。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
然后删除原来的index和data文件,将tmp文件重命名,因为他溢写的操作要有很多次。

那么stage1如何去读取这些数据呢?

ShuffledRDD中的compute方法:

在这里插入图片描述

这里就会有一个读出来的操作。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值