Shuffle是什么
在spark源码分析之stage生成中,我们讲到Spark在DAGSchduler阶段会将一个Job划分为多个Stage,在上游Stage做map工作,下游Stage做reduce工作,其本质上还是MapReduce计算框架。Shuffle是连接map和reduce之间的桥梁,它将map的输出对应到reduce输入中,这期间涉及到序列化反序列化、跨节点网络IO以及磁盘读写IO等,所以说Shuffle是整个应用程序运行过程中非常昂贵的一个阶段,理解Spark Shuffle原理有助于优化Spark应用程序。
Shuffle&Stage
Stage划分&与Shuffle关系
Spark Stage是根据对parent rdd的依赖的种类进行划分的,如下图所示:
- 窄依赖是指父RDD的每个分区只被子RDD的一个分区所使用,子RDD分区通常对应常数个父RDD分区,如上图中的C->D; D->F; E->F
- 宽依赖(Shuffle依赖)是指父RDD的每个分区可能会被下游RDD的一个或者多个分区所使用,如上图中的A->B, B,F->G。
宽依赖是划分Stage的重要标志,划分出来的两个Stage,上一个Stage执行的是Shuffle的Map操作,下一个Stage执行的是Shffule的Reduce操作,所以上面依赖的整个执行过程如下图所示:
总结起来:宽依赖划分了Stage,中间涉及了Shuffle过程,前一个stage的通过ShuffleMapTask进行Shuffle write, 把数据存储在blockManager上面, 并且把数据位置元信息上报到driver的mapOutTrack组件中,下一个stage根据数据位置元信息,进行 shuffle read,拉取上个stage的输出数据,进行数据处理。
常见Shuffle算子
Spark中常见的Shuffle算子有以下几类:
- 去重: distinct
- 聚合: reduceByKey,groupBy,groupByKey,aggregateByKey,combineByKey,sortByKey
- 重分区:coalesce,repartition
- 集合或者表操作:intersection,subtract,join
当然判断是否为shuffle,最好还是看debug出来的Lineage信息,看到中间过程有ShuffledRDD表明发生了Shuffle操作:
scala> val rdd = sc.parallelize(Array("hello world", "hah xx"