Spark常见调优方式

Spark调优
  • 资源调优合理设置Driver和Executor的个数以及他们的核数和内存大小

  • RDD优化

    • RDD复用,对RDD进行算子时,要避免相同的算子和计算逻辑下对RDD进行重复计算

    • RDD持久化,当多次对同一个RDD执行算子操作时,每一次都会对这个RDD以之前的夫RDD

      重新计算,要避免这种情况,要对多次使用的RDD进行持久化

  • 并行度调节

    • 理想的并行度设置,是让并行度和资源相匹配,就是在资源允许的前提下,并行度要设置的尽可能大,达到可以充分利用集群资源。合理的设置并行度,可以提升整个Spark作业的性能和运行速度,官方推荐,task数量应该设置为Spark作业总CPU Core数量的2~3倍

      val conf = new SparkConf().set("spark.default.parallelism","500")
      
  • 广播大变量

    • 默认情况下,task中的算子中如果使用了外部的变量。每个task都会获取一份变量的副本,

      这造成了内存的极大消耗,一方面如果后续对RDD进行持久化,可能就无法将RDD数据存入内存,只能写入磁盘,磁盘IO将会严重消耗性能,另一方面task在创建对象的时候,堆内存无法存放新创建的对象,这会导致频繁的GC。

  • 使用Kryo序列化

    • 默认情况下,Spark使用的是Java的序列化机制,优点是Java的序列化机制使用方便,不需要额外的配置,在算子中使用的变量实现Serializable接口即可,缺点是Java序列化机制的效率不高,序列化速度慢并且序列化后的数据所占用的空间依然很大。
    • Kryo序列化机制比Java序列化性能提高了10倍左右,缺点是kryo不支持所有对象的序列化,同时Kryo需要用户在使用前注意需要序列化的类型,不够方便,但是从Spark2.0.0开始简单类型、简单类型数组、字符串类型的shuffing RDDs,已经默认使用Kryo序列化方式了
  • 使用高性能算子

    • 比如使用mapPartition替代map,map算子对RDD中的每一个元素进行操作,而mapPartition算子对RDD中每一个分区进行操作,优点是速度快效率高,缺点是在内存不足时会产生OOM
    • 使用foreachPartiton替代foreach,如果使用foreach算子完成对数据库的操作,由于foreach算子是遍历RDD的每条数据,因此每条数据都会建立一个数据库连接,这是对资源的极大浪费,因此对于写数据库操作,我们应当使用foreachPartition。
    • 使用filter与coalesce配合使用:在Spark任务中我们经常会使用filter算子完成对RDD中数据的过滤,在任务初始阶段从各个分区加载到的数据量是相近的,但是一旦经过filter过滤后,每个分区的数据量有可能会存在较大差异,对数据量较大的分区需要需要增加分区的数量,对数据量较小的分区,需要缩减分区的数量。
    • 使用repartition解决Spark SQL低并行度的问题
    • 使用reduceByKey 预聚合
  • Shuffle调优

    • 调节map端缓冲区的大小

      在Spark任务运行的过程中,如果shuffle的map端处理的数据量比较大,但是map端缓冲区的大小时固定的,可能会出现map端缓冲数据频繁的spill溢写到磁盘文件的情况。通过调节map端缓冲区的大小,可以避免频繁的磁盘IO操作,从而提升Spark任务的整体性能

    val conf = new SparkConf().set(“spark.shuffle.file.buffer”,"64"
    • 调节reduce端拉取数据缓冲区大小

      在Spark Shuffle过程中,shuffle reduce task 的buffer 缓冲区大小决定了reduce task每次能够缓冲的数据量,也就是每次能够拉取的数据量,如果内存资源较为充足,适当增加拉取数据缓冲区的大小,可以减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能

      val conf = new SparkConf().set("spark.reducer.maxSizeInFlight","96")
      
    • 调节reduce端拉取数据重试次数

      Spark Shuffle过程中,reduce task拉取属于自己的数据时,如果因为网络异常等原因导致失败会自动进行重试。对于那些包含了特别耗时的shuffle操作的作业,需要增加重试最大次数,以避免由于JVM的full gc或者网络不稳定等因素导致的数据拉取失败

      val conf = new  SparkConf().set("spark.shuffle.io.maxRetries","6")
      
    • 调节reduce端拉取数据等待间隔

      在Spark Shuffle过程中,reduce task拉取属于自己的数据时,如果因为网络异常等原因导致失败会自动进行重试,在一次失败后,会等待一定时间间隔再进行重试,可以通过加大时间间隔 以增加shuffle操作的稳定性

      val conf = new SparkConf().set("spark.shuffle.io.retryWait","60s")
      
    • 调节SortShuffle排序操作阈值

      对于SortShuffleManager,如果shuffle reduce task的数量小于某一阈值则shuffle write 过程中不会进行排序操作,而是直接按照未经优化的HashShuffleManager的方式去写数据,但是最后会将每个task产生的所有临时磁盘文件合并成一个文件,并会创建单独的索引文件,当使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大,大于shuffle read task 的数量,那么此时map-side就不会进行排序,减少了排序的性能开销,但是这种方式下,依然会产生大量的磁盘文件,因此shuffle write性能有待提高

      val conf = new Sparkconf().set("spark.shuffle.sort.bypassMergeThresld",“400)
      

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值