spark性能优化

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,即提高集群部署的主机数量,这个是最有效的优化(有钱就是任性)
spark性能优化_第1张图片

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、未持久化与持久化的比较

spark性能优化_第2张图片

如上图所示的计算逻辑:
(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内存分析

spark性能优化_第3张图片
spark性能优化_第4张图片

6.2、内存参数调整

  • 指定spark执行与存储的内存比例

    spark.memory.fraction=“0.6”

  • 指定spark存储的内存比例

    spark.memory.storageFraction=“0.5”

7、JVM调优

7.1、JVM内存分析

spark性能优化_第5张图片

  • 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”

你可能感兴趣的:(spark)