文章目录
一、资源调优
下面了解在standalone
模型下的资源调优,最大就最好。
-
在部署
spark
集群中指定资源分配的默认参数
在spark
安装包的conf
下spark-env.sh
SPARK_WORKER_CORES SPARK_WORKER_MEMORY SPARK_WORKER_INSTANCES 每台机器启动 worker 数
-
在提交
Application
的时候给当前的Application
分配更多的资源
提交命令选项:(在提交 Application 的时候使用选项)--executor-cores --executor-memory --total-executor-cores
配置信息:(Application 的代码中设置或在 Spark-default.conf 中设置)
spark.executor.cores spark. executor.memory spark.max.cores
-
动态分配资源
spark.shuffle.service.enabled true //启用 External shuffle Service 服务 spark.shuffle.service.port 7337 //Shuffle Service 服务端口,必须和yarn-site 中的一致 spark.dynamicAllocation.enabled true //开启动态资源分配 spark.dynamicAllocation.minExecutors 1 //每个Application最小分配的executor数 spark.dynamicAllocation.maxExecutors 30 //每个Application最大并发分配的executor数 spark.dynamicAllocation.schedulerBacklogTimeout 1s spark.dynamicAllocation.sustainedSchedulerBacklogTimeout 5s
yarn
命令:
/opt/lzj/sparkhome/bin/spark-submit \
--class 主类 \
-master yarn-cluster \
-num-executors 100 \
-executor-cores 4 \
-driver-cores 4 \
-driver-memory 6g \
-executor-memory 8d \
-quene root. default \
--conf
jar包路径
[主类运行所需参数]\
二、并行度调优
并行度的合理调整,可以降低资源浪费,提高spark
任务的运行效率。task
的数量应该设置为sparkCPU cores
(总核数)的2-3
倍。并行度设置的是task的并行度。
-
如果读取的数据在
HDFS
中,降低block
大小,相当于提高了RDD
中partition
个数sc.textFile(xx,numPartitions)
-
sc.parallelize(xxx, numPartitions)
-
sc.makeRDD(xxx, numPartitions)
-
sc.parallelizePairs(xxx, numPartitions)
-
repartions/coalesce
repartions
增加分区;coalesce
减小分区,一般与filter
搭配 -
redecByKey/groupByKey/join ---(xxx, numPartitions)
这几个算子都是会产生shuffle的算子。 -
spark.default.parallelism 500
-
spark.sql.shuffle.partitions 200
spark.default.parallelism
并行度调节对sparksql
无效(即这个并行度只要是没有使用sparkSql
的stage
中都会生效)。一般我们的操作就是使用repartition
去增大sparksql
查询出的rdd
的分区数。 -
自定义分区器
-
如果读取数据是在
SparkStreaming
中
Receiver: spark.streaming.blockInterval—200ms
定义的是max
Direct
:读取的topic
的分区数
三、代码调优
1.避免创建重复的 RDD
val rdd1 = sc.textFile(path1)
val rdd2 = sc.textFile(path1)
这就是创建了重复的 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
的级别,必须将所有数据都复制一份副本,并发送到其他节点上,数据复制以及网络传输会导致较大的性能开销,除非是要求作业的高可用性,否则不建议使用。
3.持久化算子:
cache
:
MEMORY_ONLY
persist
:
MEMORY_ONLY
MEMORY_ONLY_SER
MEMORY_AND_DISK_SER
一般不要选择带有_2
的持久化级别。checkpoint
:- 如果一个
RDD
的计算时间比较长或者计算起来比较复杂,一般将这个RDD
的计算结果保存到HDFS
上
- 如果一个