shuffle原理及调优

一、原理概述

①什么是shuffle?

以reduceByKey为例,要把分布在集群各个节点上的数据中的同一个key对应的values集中到一块,集中到集群中同一个节点上。更严格地说,集中到同一个节点的同一个executor的task中。

集中同一个key对应的values之后,数据变成>,算子函数对values进行reduce操作,最后变成形式的数据。

每一个shuffle的前半部分stage的task,都会创建与下一个stage的task数量相同的文件。比如下一个stage有100个task,那么当前stage的每个task都会创建100个文件。并且,会将同一个key对应的values写入同一个文件;不同节点上的task,会将同一个key对应的values,写入下一个stage同一个task对应的文件中。在这个部分,task在将数据写入磁盘文件之前,会先写入内存缓存区,内存缓冲区溢满后,再spill溢写到磁盘文件中。

shuffle的后半部分stage的task,每个task都会从各个节点中,上一个stage中的task为自己创建的文件中,拉取属于自己的key,value数据,然后task会有一个内存缓冲区,对数据进行汇聚。

②有哪些常用的操作会触发shuffle?

spark中,常见的会触发shuffle的算子有:groupByKey、reduceByKey、countByKey、join,等等。

二、合并map端输出文件

在该功能不开启的情况下,如原理所述,当前stage的每个task都会为下一个stage创建和下一个stage中task数量相同的文件。比如当前stage和下一个阶段的stage都有10个task,那么当前stage的每个task会为下一个stage创建10个文件,一共是10*10=100个文件。

开启该功能后,如果每个executor只有两个cpu core,那么同时运行的task数量只有2个。这个时候,当前的stage中,先运行2个task,每个task创建10个文件,一共是2*10=20个。这2个task运行完之后,再运行后面的2个task。后面的2个task运行的时候,不再创建新的文件,而是复用前面2个task创建的文件。依次类推,直到当前stage的10个task运行结束,一共创建20个文件,和之前的100个文件相比,数量大大减少,需要写到磁盘的文件数减少,同时下一个stage阶段需要去磁盘上读取的文件数也减少,性能得到很大提升。

该功能默认不开启,可以在代码中使用new SparkConf().set("spark.shuffle.consolidateFiles", "true")来开启。

三、调节map端内存缓冲和reduce端内存占比

默认情况下,map端每个task内存缓冲的大小是32kb,reduce端内存占比是0.2,即20%。

如果需要处理的数据量比较大,比如每个task需要处理320000kb,那么需要向磁盘溢写320000/32=10000次,向磁盘溢写文件次数过多,造成大量的磁盘IO,性能下降。

reduce端拉取数据的时候,如果数据量很大,而内存占比很小,在reduce端聚合的时候,内存不够用,需要spill溢写到磁盘中。向磁盘溢写的数据量越大,后续处理需要从磁盘读取的数据量也越大。这样频繁地发生磁盘IO,会严重地影响性能。

根据上述情况,为了减少磁盘IO,可以调节map端缓存区大小和reduce端内存占比。

调节的原则是,先固定一个参数,调整另一个参数,多次销量调节。一个参数调整完之后,再调整另一个参数。

你可能感兴趣的:(大数据,Spark调优)