原则一:避免创建重复的RDD,尽可能复用同一个RDD
对于同一份数据不要创建多个RDD,对不同的数据执行算子操作时要尽可能地复用一个RDD。
原则二:对多次使用的RDD进行持久化
前面已经提到Spark中rdd内部的转换关系是一个DAG,因此对于一个RDD执行多次算子时,都会重新从源头处计算一遍,这种方式的性能是很差的。如下图所示,其中D和E代表action算子,在计算D和E时要分别从A开始计算。
有向无环图(DAG) 最好的方法就是对C进行持久化,此时Spark就会将数据保存到内存或者磁盘中,以后每次对C这个RDD进行算子操作时,都会直接从内存或磁盘中提取持久化的RDD数据,不会从源头处重新计算一遍。
原则三:尽量避免使用shuffle类算子
Spark作业运行过程中,最消耗性能的地方就是shuffle过程。shuffle过程就是将分布在集群中多个节点上的同一个key,拉取到同一个节点上,进行groupby或join等操作,reduceByKey、join、distinct、repartition等都属于shuffle算子。
原则四:使用预聚合的shuffle操作
如果有些时候实在无法避免使用shuffle操作,那么尽量使用可以预聚合的算子。预聚合就是在每个节点本地对相同的key进行一次聚合操作,多条相同的key被聚合起来后,那么其他节点再拉取所有节点上的相同key时,就会大大减少磁盘IO以及网络传输开销。下图所示,每个节点本地首先对于相同key进行了聚合。
原则五:使用高性能的算子
除了shuffle相关的算子有优化原则之外,其他的算子也都有着相应的优化原则,不一一陈述。
通过spark-env文件、程序中sparkconf和set property设置。 (1)计算量大,形成的lineage过大应该给已经缓存了的rdd添加checkpoint,以减少容错带来的开销。 (2)小分区合并,过小的分区造成过多的切换任务开销,使用repartition。
spark调优比较复杂,但是大体可以分为三个方面来进行,1)平台层面的调优:防止不必要的jar包分发,提高数据的本地性,选择高效的存储格式如parquet,2)应用程序层面的调优:过滤操作符的优化降低过多小任务,降低单条记录的资源开销,处理数据倾斜,复用RDD进行缓存,作业并行化执行等等,3)JVM层面的调优:设置合适的资源量,设置合理的JVM,启用高效的序列化方法如kyro,增大off head内存等等
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。