Spark关闭预检查内存
今天在测试Spark集群的时候,因为我需要看下自己开发的RPC接口对原生的Spark参数支持是否完整,所以需要对各种参数做测试,中间碰到一个问题是:
Spark context stopped while waiting for backend |
看了原因是因为我设置的内存参数过高,而机器实际的物理内存不足,因此无法正常拉起一个Spark作业,Yarn的nodemanager节点会对提交上来的任务(本例为spark on yarn)进行内存可分配性检查,涉及到对物理内存和虚拟内存的检查,当机器内存性能不太高时,无法通过内存检查。
于是我打算关闭此选项,来通过不预检内存来尝试启动程序的目的(受限于物理内存的制约,可能会失败)。
关闭的方法是在yarn-site.xml中添加如下配置项,并重启yarn,程序在 “–driver-memory 24G –executor-memory 6G “的参数下已可以成功运行。
<property> |
这里需要了解一些Spark的向Yarn申请资源的计算规则,也就是知道基于参数,Yarn分配多少资源给Spark作业,
Spark任务会根据自己的executors的个数向yarn申请对应个数的container来跑任务,每个executor相当于一个JVM进程。
除了跑任务的container,Yarn会额外给每一个spark任务分配一个container用来跑ApplicationMaster进程,整个进程用来调控spark任务。
对于Spark任务,ApplicationMaster内存大小由上面的spark.driver.memory控制。
Yarn两个默认内存参数
- yarn.scheduler.minimum-allocation-mb 每个container的最小内存值
- yarn.scheduler.maximum-allocation-mb 每个container的最大内存值
也就是说:
- 如果你设置的spark.executor.memory参数值比yarn.scheduler.minimum-allocation-mb小,那yarn生成的container内存大小会默认会使用yarn.scheduler.minimum-allocation-mb的值。
- 如果你设置的spark.executor.memory参数值比yarn.scheduler.maximum-allocation-mb大,那yarn生成的container内存大小默认会使用yarn.scheduler.maximum-allocation-mb的值。
- 还有个隐藏的条件,yarn生成的container内存大小必须是yarn.scheduler.minimum-allocation-mb值的整数倍
Spark on yarn有一个memoryOverhead的概念,是为了防止内存溢出额外设置的一个值,可以用spark.yarn.executor.memoryOverhead参数手动设置,如果没有设置,默认memoryOverhead的大小由以下公式计算:
memoryOverhead = max(spark.executor.memory * 0.07,384)
// Executor memory in MB. |
Yarn对Spark任务内存的申请计算方式
举个例子:
我们线上yarn的yarn.scheduler.minimum-allocation-mb设置的是2G |
按照这部分参数,计算出来申请的内存大小应该是:
56 * 2G + 5G = 117G |
但是任务提交之后,从yarn的资源管理界面看到申请的内存大小为:
235520M = 230G |
几乎是理论值的两倍。
背后的计算逻辑是:
executor使用的内存计算
memoryOverhead = max(spark.executor.memory * 0.07,384) = max(2 * 1024 * 0.07,384) = 384M |
则一个executor实际要使用的内存大小为:
totalMemory = spark.executor.memory + memoryOverhead = 2 * 1024 + 384 = 2432M |
又因为yarn.scheduler.minimum-allocation-mb = 2G = 2048M
由yarn的container内存大小的性质可知,container内存大小必须是yarn.scheduler.minimum-allocation-mb的整数倍,我们现在需要的内存大小是 2432M,而yarn.scheduler.minimum-allocation-mb是2048M。
那么比2432M大且是2048M整数倍的最小值是4096M=4G,所以实际上yarn为spark申请的每个container的内存大小并不是我们设置的2G,而是4G
这样,我们有56个executor,也就是会申请56个container,则消耗的总内存是 56 * 4G = 224G
driver的内存计算
计算方式和上面一样:
memoryOverhead = max(spark.driver.memory * 0.07,384) = max(5 * 1024 * 0.07,384) = 384M |
则driver实际要使用的内存大小为:
totalMemory = spark.driver.memory + memoryOverhead = 5 * 1024 + 384 = 5504M |
同理,比5504M大且是2048M的整数倍的最小值是6144M=6G 故driver实际申请的内存大小是6G
所以整个spark任务最终申请的总内存大小为 224G + 6G = 230G。
扫码手机观看或分享: