@R星校长
Spark优化【Spark优化内容】
主要内容
- Spark资源优化
- Spark并行度优化
- Spark代码优化
- 内存调优
- Sparkshuffle优化
- 堆外内存优化
- 解决数据倾斜
第一节 资源优化
1) .搭建Spark集群的时候要给Spark集群足够的资源(core,memory)
在spark安装包的conf下spark-env.sh
SPARK_WORKER_CORES
SPARK_WORKER_MEMORY
SPARK_WORKER_INSTANCE
2) .在提交Application的时候给Application分配更多的资源。
提交命令选项:(在提交Application的时候使用选项)
--executor-cores
--executor-memory
--total-executor-cores
配置信息:(在Application的代码中设置
在Spark-default.conf中设置)
spark.executor.cores
spark.executor.memory
spark.max.cores
第二节 并行度优化
原则:一个core一般分配2~3个task,每一个task一般处理1G数据(task的复杂度类似wc)
提高并行度的方式:
1) sc.textFile(xx,minnumpartition)
2) sc.parallelize(xx,num)
3) sc.makeRDD(xx,num)
4) sc.parallelizePairs(xx,num)
5) reduceByKey,join,distinct
6) repartition/coalesce
7) spark.default.parallelism
8) spark.sql.shuffle.partitions
9) 自定义分区器
10) SparkStreaming: Direct模式
第三节 代码优化
1. 避免创建重复的RDD,复用同一个RDD
2. 对多次使用的RDD进行持久化
如何选择一种最合适的持久化策略?
默认情况下,性能最高的当然是MEMORY_ONLY,但前提是你的内存必须足够足够大,可以绰绰有余地存放下整个RDD的所有数据。因为不进行序列化与反序列化操作,就避免了这部分的性能开销;对这个RDD的后续算子操作,都是基于纯内存中的数据的操作,不需要从磁盘文件中读取数据,性能也很高;而且不需要复制一份数据副本,并远程传送到其他节点上。但是这里必须要注意的是,在实际的生产环境中,恐怕能够直接用这种策略的场景还是有限的,如果RDD中数据比较多时(比如几十亿),直接用这种持久化级别,会导致JVM的OOM内存溢出异常。
如果使用MEMORY_ONLY级别时发生了内存溢出,那么建议尝试使用MEMORY_ONLY_SER级别。该级别会将RDD数据序列化后再保存在内存中,此时每个partition仅仅是一个字节数组而已,大大减少了对象数量,并降低了内存占用。这种级别比MEMORY_ONLY多出来的性能开销,主要就是序列化与反序列化的开销。但是后续算子可以基于纯内存进行操作,因此性能总体还是比较高的。此外,可能发生的问题同上,如果RDD中的数据量过多的话,还是可能会导致OOM内存溢出的异常。
如果纯内存的级别都无法使用,那么建议使用MEMORY_AND_DISK_SER策略,而不是MEMORY_AND_DISK策略。因为既然到了这一步,就说明RDD的数据量很大,内存无法完全放下。序列化后的数据比较少,可以节省内存和磁盘的空间开销。同时该策略会优先尽量尝试将数据缓存在内存中,内存缓存不下才会写入磁盘。
通常不建议使用DISK_ONLY和后缀为_2的级别:因为完全基于磁盘文件进行数据的读写,会导致性能急剧降低,有时还不如重新计算一次所有RDD。后缀为_2的级别,必须将所有数据都复制一份副本,并发送到其他节点上,数据复制以及网络传输会导致较大的性能开销,除非是要求作业的高可用性,否则不建议使用。
持久化算子:
cache:
MEMORY_ONLY
persist:
MEMORY_ONLY
MEMORY_ONLY_SER
MEMORY_AND_DISK_SER
一般不要选择带有_2的持久化级别。
checkpoint:
① 如果一个RDD的计算时间比较长或者计算起来比较复杂,一般
将这个RDD的计算结果保存到HDFS上,这样数据会更加安全。
② 如果一个RDD的依赖关系非常长,也会使用checkpoint,会
切断依赖关系,提高容错的效率。
3. 尽量避免使用shuffle类的算子
使用广播变量来模拟使用join,使用情况:一个RD