从去年五月份开始做了一个基于Spark计算平台的项目,现在已接近尾声,项目期间做了一些性能调优的工作,于此处做个总结,并分享给需要的人和以后的自己。
一、集群参数调优上
1.根据实际的集群环境和数据处理量,对集群参数合理地进行调配,如各个worker的内存大小等参数需要重点调配
2.一些策略选择上,如将数据persist到内存或外存时选择的序列化方案,可通过参数进行调配,Spark默认使用的是Java中的序列化方式,其性能较差,即序列化和反序列话的效率较低,可选用Spark提供的另一种序列化工具kryo,优化序列化性能。
二、代码编写上进行调优
1.将频繁使用的RDDcache到内存中去,目标是对内存中的数据重用最大化,尤其是对多Job的Application比较适用,针对两部分数据:
1)把重用率高的初始RDDcache到内存中去,如果这个RDD被多个宽依赖操作重用或者多个Job重用,则可以将将其cache到内存中去,如若不然,每次使用时初始RDD都会重新从磁盘读取,自然I/O代价较高,性能较差。
2)将重用率高的shuffle后的结果cache到内存中去,如果这个结果会有多个Job公用,可以达到充分重用内存中数据的目的
3)为了加速对一些小块数据的读取,不需要每次使用都涉及到远程传输,则可将其Broadcast出去
2.Join操作优化可考虑的比较多,join操作通常是SparkJob执行的瓶颈,所以优化Join操作至关重要。Join的瓶颈点在于会涉及到数据Shuffle,也就是产生大量的网络传输,故而优化Join的关键点在于尽量减少Shuffle操作和优化shuffle操作
1)减少shuffle操作:对即将进行Join操作的两个数据集以同样的方式进行Hash分区。
2)优化shuffle:①可通过调参数更改shuffle数据块的存储方式,默认是将shuffle数据块映射成为文件,这样会产生大量的小文件(个数为map任务的个数*reduce任务的个数),大量的小文件会对磁盘和文件系统的性能造成很大的影响,所以可以通过参数配置,选择另一种shuffle数据块存储方式,可以将一个小文件进行合并,从而减少shuffle操作产生的文件数,达到优化shuffle性能的目的
②可通过调参数spark.shuffle.blockTransferService更改shuffle数据块的读取和传输方式,可通过具体的网络情况进行选择。default:netty
③其他参数:
spark.shuffle.manager:Hash Based Shuffle和Sort Based Shuffle(default)
spark.shuffle.spill:true/false
spark.shuffle.spill:决定了当Shuffle过程中使用的内存达到总内存多少比例的时候开始Spill。default:0.2,它直接影响了Spill的频率和GC。
3 )filter操作上推。即将数据过滤操作上推到Join操作之前进行,目的很直观,就是使得进行Join操作的数据越小越好,看起来简单,却也是最行之有效的方法。
3.一些策略选择上,如将数据persist到内存时是否序列化的问题,序列化实际上就是用时间换空间,进行序列化和反序列化都需要耗费CPU资源,如将数据cache到内存里不够用,可考虑序列化。
三、针对一些典型的数据问题进行优化,如数据倾斜严重、Straggler等问题
如果数据倾斜严重,会造成集群中部分机器的负载较重,此时需要考虑更好的分区策略均衡数据分布
如果存在部分机器是Straggler的问题,可通过调配参数,任务执行前提前预估这个集群中各机器的质量,以调配后面的任务调度使性能达到最优。