如何设置Spark Executor Memory的大小

前边文章的铺垫终于可以运用到实际项目的开发及调优中了,下面我们就来看看实际集群环境下的Spark配置吧

一、Spark内存使用大体上的两类

执行内存存储内存。其中执行内存用于shuffle、join、sort、aggregation等操作的计算使用。存储内存用于cache对象、存储广播数据等。

二、Executor内存设置小了会发生的现象

1、频繁GC,GC超限,CPU大部分时间用来做GC而回首的内存又很少,也就是executor堆内存不足。
2、java.lang.OutOfMemoryError内存溢出,这和程序实现强相关,例如内存排序等,通常是要放入内存的数据量太大,内存空间不够引起的。
3、数据频繁spill到磁盘,如果是I/O密集型的应用,响应时间就会显著延长。

三、Spark内存模型

注:2.0+和2.0以前的版本默认值不同(spark.memory.fraction Spark2.0+默认值0.6 Spark1.6默认值0.75)
在这里插入图片描述

图1 Spark统一内存管理模型示意图

四、设置Executor内存大小的时候要考虑的因素

以下情况适用于应用可以使用全部内存资源的情况。
1、物理可用内存大小。
2、对应每个core,给操作系统预留内存。
3、如果使用yarn进行资源分配,yarn执行资源分配需要的内存。
4、排除掉图中保留的300M系统内存。
5、看程序中有没有使用broadcast,如果使用了broadcast,估算broadcast数据可能占用多少空间。
6、根据业务特性估算聚合或者洗牌操作中拉取数据时可能使用多少内存。一般程序中都会对数据集按某个业务字段进行分区,大致估算时间步长内分区占用的内存大小可能是多少。
7、程序中是否会对某个数据集进行cache,考虑cache数据大小。
8、考虑这些数据是否被压缩。当然,压缩数据节省空间但是消耗额外CPU时间。

  从前面的文章中我们能够看出,Spark处理速度随着内存容纳数据的比例线性提升。所以在有条件的情况下加大内存资源,对性能提升有显著帮助。当然,如果资源实在有限,适当地减小并发任务量和时间步内的数据总量,以此来保证每个任务的独享资源最大化,保证不发生内存溢出,当然这种情况下,频繁GC、频繁spill磁盘大概率发生,响应性能没法保证,当然通过前边文章我们能知道,同等条件下还是要比hadoop快不少的,可以看看前边的文章。

五、举例说明:

spark-submit \
  --master yarn \
  --deploy-mode client \
  --driver-memory 2G \
  --executor-memory 10G \
  --num-executors 25 \
  --executor-cores 4 \
  --queue ltemr \
  --conf "spark.driver.extraJavaOptions=-Dhdp.version=3.1.0.0-78" \
  --conf "spark.yarn.am.extraJavaOptions=-Dhdp.version=3.1.0.0-78" \
  --jars $(echo /home/ltemr/oozie_signal/spark/lib/*.jar | tr ' ' ',') \
  --properties-file conf/spark-properties-uemr.conf \
  uemr-streaming-driver-1.0-SNAPSHOT.jar \
  UEMRFixLocationDriver

从提交命令来看,配置的executor内存是10G,部署模式是yarn-client

在spark.memory.fraction设置为0.75的情况下,每个executor真正可以使用内存:
storage memory
=(10G-300MB)x0.75x0.5
=3727.5 M
execution memory
=(10G-300MB)x0.75x0.5
=3727.5 M


每个Task最多可用资源:
storage memory
=((10G-300MB)x0.75x0.5))/4
=931.875 M
execution memory
=((10G-300MB)x0.75x0.5))/4
=931.875 M

六、补充

1、实际部署spark应用时一般需要配置如下三个参数值

1)、spark.memory.fraction=0.6

  该参数表示Spark内存比例。如果在你的代码逻辑中很少用到一些使用如List,Map等等你主动建立的数据结构(这些会在UserMemory部分),并且也只是存储少量的数据,那么适当提高这个参数值,比如提高到0.75等,这样一来更多的空间就能被Spark当做存储和执行使用。

2)、spark.memory.storageFraction=0.5

  这个参数的伸缩性很大,需要看执行过程会不会发生shuffle、join、sort、aggregation等操作,如果你的代码只是很简单的转换操作,不存在任何shuffle操作,这时你可以将spark.memory.storageFraction的值设置大一点(甚至1也可以,比如你的应用只是简单的map操作),这样可以更多的内存就可以容纳RDD,能避免一些落盘,反序列化等操作开销,也能提升些效率。相反,对于涉及shuffle等执行逻辑的应用,对应执行内存可以多给点,当然这个执行内存的调整,需要跟很多调优参数一起结合才能发挥好的作用,这里不细说。通常情况下,这个参数默认就可以。另外一个原则是,在不知道一个参数的作用的情况下,就让它保持默认就可以,否则容易埋坑。

3)、spark.executor.memoryOverhead=1024M

  这个参数表示每个executor配备的可使用的堆外内存大小。在调spark应用程序时可能经常会碰到OOM,然后错误日志中提示让提高这个参数指定的值的情况。这种情况其实多发生在有数据倾斜的情况,这个调整经常是治标不治本,在某些稍微倾斜的情况下兴许有用,解决倾斜是根本。当然,如果资源充足,这个配置大点当然有好处,默认情况是配置的executor内存容量的10%。

2、那到底怎么看配置的executor内存值及参数设置是否合理呢?

  上边描述都了解的情况下,先估出一个初始值,然后在测试运行时去看对应的web管理界面,看具体task执行时对应的GC时长和执行任务时长,如果执行GC所占时间比重过大,说明你配置的内存容量不合理,系统频繁在做GC。

3、具体怎么样算调整到位呢?

  TimeLine显示状态合理(通通绿条),GC时长合理(占比很小),系统能够稳定运行。
  当然内存给太大了也是浪费资源,合理的临界值是在内存给到一定程度,对运行效率已经没有帮助了的时候,就可以了。
  其实这些在web界面都能根据,调优时很好的利用web界面给出的指标测量值就行。

  最后,在实际的部署环境中还是要根据实际情况考虑每个Executor分配的内存大小,在性能和资源之间做出权衡。

  • 14
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值