1、分配更多的资源
1.1、分配哪些资源
executor-memory、executor-cores、num-executor
1.2、在哪里设置这些资源
在生成环境中,提交spark任务时,使用spark-submit shell脚本,可以调整对应的参数
提交任务的脚本
spark-submit \
--master saprk://node01:7077 \
--class cn.tuyou.Wordcount \
--num-executor 3 \ //配置executor的数量
--driver-memory 5g \ //配置driver的内存(无太大影响)
--executor-memory 1g \ //配置每一个executor的内存大小
--executor-cores 3 \ //配置每一个executor的cpu个数
1.3、设置这些资源为什么能优化
提高executor-memory,能提高executor的内存大小,本质提高的读取文件的速度
提高executor-cores,能提高每个executor的cpu个数,本质增强的处理task的并行执行能力
提高num-executor,即提高集群部署的主机数量,这个是最有效的优化(有钱就是任性)
2、提高并行度
假设,一个application设置的分区数=10个,我们设置的cpu总核数=50个,假设每个task要处理的数据量1G。
目前cpu资源同一时间可以运行50个task,但是目前我们只有10个task,所以会有40个cpu处于空闲状态。
那么如果我们将分区数设置为50个,那每一个taks处理的数据量是0.2G,同一时间,50个task都可以运行。然后整个的运行效率就有所提升。在项目中分区数一般设置为cpu核数的2-3倍最佳
2.1、设置分区数的方式
- 参数设置
- sparkCore参数:spark.default.parallelism
- sparkSQL参数:spark.sql.shuffle.partitions
- 通过算子:repartition、coalese
3、RDD重用与持久化
3.1、未持久化与持久化的比较

如上图所示的计算逻辑:
(1)当第一次使用rdd3做相应的算子操作得到rdd4的时候,就会从rdd1开始计算,先读取HDFS上的文件,然后对rdd1 做对应的算子操作得到rdd2,再由rdd2计算之后得到rdd3,rdd3计算之后得到rdd4。同样为了计算得到rdd5,前面的逻辑会被重新计算。
(2)默认情况下多次对一个rdd执行算子操作,去获取不同的rdd,都会对这个rdd及之前的父rdd全部重新计算一次。 这种情况在实际开发代码的时候会经常遇到,但是我们一定要避免一个rdd重复计算多次,否则会导致性能急剧降低。 总结:可以把多次使用到的rdd,也就是公共rdd进行持久化,避免后续需要,再次重新计算,提升效率。
3.2、如何对rdd进行持久化
- 可以调用rdd的cache或者persist方法。
- cache方法默认是把数据持久化到内存中 ,例如:rdd.cache ,其本质还是调用了persist方法
- persist方法中有丰富的缓存级别,这些缓存级别都定义在StorageLevel这个object中,可以结合实际的应用场景合理的设置缓存级别。例如: rdd.persist(StorageLevel.MEMORY_ONLY),这是cache方法的实现。
4、序列化
-
比如当对rdd进行持久化时,如果选择缓存级别选了磁盘备份,就会涉及到序列化;
在计算之后的结果内存放不下,spark也会涉及序列化;
选择正确的序列化本质上可以减少占用的空间和便于网络传输; -
项目中一般使用kryo序列化,使用方式,在代码中设置参数:
SparkSession.builder().config(“spark.serializer” , “org.apache.spark.serializer.KryoSerializer”)
Spark支持使用Kryo序列化机制。Kryo序列化机制,比默认的Java序列化机制,速度要快,序列化后的数据要更小,
大概是Java序列化机制的1/10。
5、本地化等待时间
- 设置参数:“spark.locality.wait”例如设置为“8s”
- 首先采用最佳的方式,等待8s后降级,还是不行,继续降级…,最后还是不行,只能够采用最差的。
- 本地化级别
process_local:进程本地化
node_local: 节点本地化
rack_local: 机架本地化
any: 无限制 - 查看task的本地化的级别,可以打开sparkUI界面查看,
- 也可以把程序提交到spark集群中运行,注意观察日志,spark作业的运行日志,推荐大家在测试的时候,先用client模式,在本地就直接可以看到比较全的日志。 日志里面会显示,starting task … PROCESS LOCAL、NODE LOCAL…
6、内存比例调优
6.1、executor内存分析


6.2、内存参数调整
- 指定spark执行与存储的内存比例
spark.memory.fraction=“0.6”
- 指定spark存储的内存比例
spark.memory.storageFraction=“0.5”
7、JVM调优
7.1、JVM内存分析

- 1、初始创建对象的时候,对象放在Eden中。
- 2、随时间的流逝,Eden中存放的对象越来越多,当Eden区域满了的时候,会进行minor GC,会将Eden中还在使用的对象放入到survivor0中,不需要的对象清除掉,清除掉之后Eden就变空了
- 3、Eden中有可以重新接纳对象,随时间的流逝,Eden中存放的对象越来越多,当Eden区域满了的时候,又会进行minor GC,会将Eden与Survivor中还在使用的对象放入到survivor1中,Eden与survivor0中不再使用的对象清除掉
- 4、循环第3个步骤
- 5、当survivor中空间不足,会将还在使用的对象放入到老年代中
- 6、循环3-5的步骤
- 7、随着时间的流逝,老年代中空间不足,这时候就需要major GC(即full GC),full GC的时候,进行对暂停一切操作,优先GC。这时候就可能还会出现拉取shuffle数据失败。
7.2、GC调优参数
- 如果在sparkUI发现GC的时间特别长,证明存储对象的内存空间过小,这时候需要增大内存
- 增大内存有两种方式:一种是直接将executor-memory设置大一点,
- 第二种就是将执行与存储的内存比例调小
- 如果在spark任务中存储的数据比较小,就可以将存储的内存比例调小,将更多的空间给执行区
- 如果在GC的时候拉取shuffle数据失败,会有一个重试次数,如果重试之后,任然没有拉取到数据,任务报错,停止执行,针对这个问题,可以调整拉取shuffle失败的参数,可以有效解决
- spark.shuffle.io.maxRetries=“6”
- spark.shuffle.io.retryWait=“10s”

722



被折叠的 条评论
为什么被折叠?



