Spark调优-参数及配置

1.参数调优

1.1 资源类

1.1.1 num-executors

该参数主要用于设置该应用总共需要多少executors来执行,Driver在向集群资源管理器申请资源时需要根据此参数决定分配的Executor个数,并尽量满足所需。在不带的情况下只会分配少量Executor。

spark-submit时若带了–num-executors参数则取此值, 不带时取自spark.executor.instances配置,若没配置则取环境变量SPARK_EXECUTOR_INSTANCES的值,若其未设置,则取默认值DEFAULT_NUMBER_EXECUTORS=2。

 /**
   * Getting the initial target number of executors depends on whether dynamic allocation is
   * enabled.
   * If not using dynamic allocation it gets the number of executors requested by the user.
   */
  def getInitialTargetExecutorNumber(
      conf: SparkConf,
      //DEFAULT_NUMBER_EXECUTORS 值为2
      numExecutors: Int = DEFAULT_NUMBER_EXECUTORS): Int = {
    if (Utils.isDynamicAllocationEnabled(conf)) {
    //动态分配场景下没细看
      val minNumExecutors = conf.get(DYN_ALLOCATION_MIN_EXECUTORS)
      val initialNumExecutors = Utils.getDynamicAllocationInitialExecutors(conf)
      val maxNumExecutors = conf.get(DYN_ALLOCATION_MAX_EXECUTORS)
      require(initialNumExecutors >= minNumExecutors && initialNumExecutors <= maxNumExecutors,
        s"initial executor number $initialNumExecutors must between min executor number " +
          s"$minNumExecutors and max executor number $maxNumExecutors")

      initialNumExecutors
    } else {
      val targetNumExecutors =
        sys.env.get("SPARK_EXECUTOR_INSTANCES").map(_.toInt).getOrElse(numExecutors)
      // System property can override environment variable.
      配置优先级高于环境变量,环境变量不存在时才用numExecutors即DEFAULT_NUMBER_EXECUTORS=2
      conf.get(EXECUTOR_INSTANCES).getOrElse(targetNumExecutors)
    }
  }

这个值得设置还是要看分配的队列的资源情况,太少了无法充分利用集群资源,太多了则难以分配需要的资源。

1.1.2 executor-memory

设置每个executor的内存,对Spark作业运行的性能影响很大。一般4-8G就差不多了,当然还要看资源队列的情况。num-executor*executor-memory的大小绝不能超过队列的内存总大小。

1.1.3 executor-cores

设置每个executor的cpu核数,其决定了每个executor并行执行task的能力。Executor的CPU core数量设置为2-4个即可。弹药注意,num-executor*executor-cores也不能超过分配队列中cpu核数的大小。具体的核数的设置需要根据分配队列中资源统筹考虑,取得Executor,核数,及任务数的平衡。对于多任务共享的队列,更要注意不能将资源占满。

1.1.4 driver-memory

运行sparkContext的Driver所在所占用的内存,通常不必设置,设置的话1G就足够了,除非是需要使用collect之类算子经常需要将数据提取到driver中的情况。

1.1.5 spark.default.parallelism

此参数用于设置每个stage经TaskScheduler进行调度时生成task的数量,此参数未设置时将会根据读到的RDD的分区生成task,即根据源数据在hdfs中的分区数确定,若此分区数较小,则处理时只有少量task在处理,前述分配的executor中的core大部分无任务可干。

通常可将此值设置为num-executors*executor-cores的2-3倍为宜,如果与其相近的话,则对于先完成task的core则无任务可干。2-3倍数量关系的话即不至于太零散,又可是的任务执行更均衡。

1.1.6 spark.storage.memoryFraction

该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。即Executor中可以用来保存持久化的RDD数据默认占了60%。根据Spark应用中RDD持久化操作的多少可以灵活调整这个比例,即持久化需要的内存多久放大此比例,免得内存不够用而不能持久化或转存到磁盘中,如果持久化操作少儿shuffle的操作多则可降低这个值。

1.1.7 spark.shuffle.memoryFraction

该参数用于设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。也就是说,Executor默认只有20%的内存用来进行该操作。shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时 就会极大地降低性能。

参见spark.shuffle.storageFraction,同理如果RDD持久化操作少而shuffle操作多则赢提高shuffle操作的内存占比,避免shuffle执行过程中内存不够。

一些实现细节

getMaxExecutionMemory

得到Executor中可用执行内存,计算为(systemMaxMemory * memoryFraction * safetyFraction).toLong,其中

   val memoryFraction = conf.getDouble("spark.shuffle.memoryFraction", 0.2)
    val safetyFraction = conf.getDouble("spark.shuffle.safetyFraction", 0.8)
getMaxStorageMemory

最大能存储的内存也就总内存的0.6*0.9=54%

/**
   * Return the total amount of memory available for the storage region, in bytes.
   */
  private def getMaxStorageMemory(conf: SparkConf): Long = {
    val systemMaxMemory = conf.getLong("spark.testing.memory", Runtime.getRuntime.maxMemory)
    val memoryFraction = conf.getDouble("spark.storage.memoryFraction", 0.6)
    val safetyFraction = conf.getDouble("spark.storage.safetyFraction", 0.9)
    (systemMaxMemory * memoryFraction * safetyFraction).toLong
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值