Spark性能调优(四)---shuffle调优

1.原理概述

1.1什么是shuffle

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

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

         每一个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会有一个内存缓冲区,对数据进行汇聚。

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

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

2.常见的shuffle参数调优

2.1合并map端输出文件

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

        在该功能不开启的情况下,如原理所述,当前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阶段需要去磁盘上读取的文件数也减少,性能得到很大提升。

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

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

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

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

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

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

       调整从0.2,0.3,0.4....

2.3调节shuffle write task的buffer大小

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

2.4设置shuffle read task的buffer缓冲大小

       默认值为48M,可能通过spark.reducer.maxSizeInFlight设置。

       参数说明:该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。

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

2.5调节reduce端拉取数据失败后重试的次数

       默认值是3次,可能通过spark.shuffle.io.maxRetries进行设置。

       参数说明:shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,是会自动进行重试的。该参数就代表了可以重试的最大次数。如果在指定次数之内拉取还是没有成功,就可能会导致作业执行失败。

      调优建议:对于那些包含了特别耗时的shuffle操作的作业,建议增加重试最大次数(比如60次),以避免由于JVM的full gc或者网络不稳定等因素导致的数据拉取失败。在实践中发现,对于针对超大数据量(数十亿~上百亿)的shuffle过程,调节该参数可以大幅度提升稳定性

2.6调节reduce端每次重试拉取数据的等待间隔

      默认值为5s,可能通过spark.shuffle.io.retryWait进行调整。

      参数说明:具体解释同上,该参数代表了每次重试拉取数据的等待间隔,默认是5s。

      调优建议:建议加大间隔时长(比如60s),以增加shuffle操作的稳定性

2.7设置ShuffleManager的类型

       默认值为sort,可能通过spark.shuffle.manager设置。

       参数说明:该参数用于设置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。

2.8修改bypass机制阈值

       默认值200,可能通过spark.shuffle.sort.bypassMergeThreshold进行调整。

       参数说明:当ShuffleManager为SortShuffleManager时,如果shuffle read task的数量小于这个阈值(默认是200),则shuffle write过程中不会进行排序操作,而是直接按照未经优化的HashShuffleManager的方式去写数据,但是最后会将每个task产生的所有临时磁盘文件都合并成一个文件,并会创建单独的索引文件。

       调优建议:当你使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大一些,大于shuffle read task的数量。那么此时就会自动启用bypass机制,map-side就不会进行排序了,减少了排序的性能开销。但是这种方式下,依然会产生大量的磁盘文件,因此shuffle write性能有待提高。

关于shuffle 参数的说明:

    1.参数一般成倍增加或者减少
    2.可以再提交任务时,使用 -conf 来进行指定,这样比在代码之中或者spark-defaults.conf之中较好(相当于写死)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值