Spark 2.2 内存占用计算公式

在Spark内存管理调优中,我们需要重点关注的有两类内存:ExecutionMemory and storageMemory。ExecutionMemory用于spark计算中的shuffles、 joins、sorts 、 aggregations这些操作,storageMemory用于缓存数据和保存广播变量数据 。

下面参数均已spark2.2为准,不同版本会有些差异

一、Spark 内存管理
(1)spark内存管理源码入口:SparkEnv.scala,代码片段如下
val useLegacyMemoryManager = conf.getBoolean("spark.memory.useLegacyMode", false)
val memoryManager: MemoryManager =
if (useLegacyMemoryManager) {
new StaticMemoryManager(conf, numUsableCores)
} else {
UnifiedMemoryManager(conf, numUsableCores)
}
通过源码可知,现在的spark内存管理有两种:静态内存管理StaticMemoryManager和统一内存管理UnifiedMemoryManager,通过参数spark.memory.useLegacyMode控制


(2)静态内存管理内存计算公式(源码见StaticMemoryManager.scala):
ExecutionMemory = systemMemory *spark.shuffle.memoryFraction*spark.shuffle.safetyFraction=executor-memory*0.2*0.8
storageMemory = systemMemory*spark.storage.memoryFraction*spark.storage.safetyFraction=executor-memory*0.6*0.9


(3)统一内存管理内存计算公式(源码见UnifiedMemoryManager.scala):
预留内存reservedMemory=300M
假设spark 应用分配的executor内存为systemMemory=2G可(通过参数--executor-memory 2g设置),systemMemory实际值要比设置executor-memory的稍小
ExecutionMemory + storageMemory) = (systemMemory-reservedMemory)spark.memory.fraction =(2048-300)*0.6=1048.8M (实际会比该值稍小)
storageMemory= (systemMemory-reservedMemory) spark.memory.fraction * spark.memory.storageFraction=(2048-300)*0.6*0.5=524.4M
Spark 2.2 内存占用计算公式

二、spark on yarn内存分配

(1) 相关参数介绍

yarn最小分配单位是container
关于Spark On YARN相关的配置参数,请参考Spark配置参数。本文主要讨论内存分配情况,所以只需要关注以下几个内心相关的参数:
spark.driver.memory:默认值512m
spark.executor.memory:默认值512m
spark.yarn.am.memory:默认值512m
spark.yarn.executor.memoryOverhead:值为executorMemory * 0.1, with minimum of 384
spark.yarn.driver.memoryOverhead:值为driverMemory * 0.1, with minimum of 384
spark.yarn.am.memoryOverhead:值为AM memory * 0.1, with minimum of 384
注意:
--executor-memory/spark.executor.memory 控制 executor 的堆的大小,但是 JVM 本身也会占用一定的堆空间,比如内部的 String 或者直接 byte buffer,spark.yarn.XXX.memoryOverhead属性决定向 YARN 请求的每个 executor 或dirver或am 的额外堆内存大小,默认值为 max(384, 0.1 * spark.executor.memory)
在 executor 执行的时候配置过大的 memory 经常会导致过长的GC延时,64G是推荐的一个 executor 内存大小的上限。
HDFS client 在大量并发线程时存在性能问题。大概的估计是每个 executor 中最多5个并行的 task 就可以占满写入带宽。
另外,因为任务是提交到YARN上运行的,所以YARN中有几个关键参数,参考YARN的内存和CPU配置
yarn.app.mapreduce.am.resource.mb:AM能够申请的最大内存,默认值为1024MB
yarn.nodemanager.resource.memory-mb:nodemanager能够申请的最大内存,默认值为8192MB
yarn.scheduler.minimum-allocation-mb:调度时一个container能够申请的最小资源,默认值为1024MB
     yarn.scheduler.maximum-allocation-mb:调度时一个container能够申请的最大资源,默认值为8192MB
           yarn.scheduler.increment-allocation-mb :container内存增量,每次增加申请的内存是该值的整数倍,默认值为1G

(2)spark on yarn内存计算公式:
1、spark on yarn申请的container数=num-executors+1  (AM会占用一个container,一个executor占用 一个container)

2、executor需要申请的总内存:total=executor-memory+max(executor-memory*0.1,384)

3、executor所在container实际申请的内存分两种情况:

(1) total <= yarn.scheduler.minimum-allocation-mb,则实际分配内存大小为yarn.scheduler.minimum-allocation-mb
(2)total > yarn.scheduler.minimum-allocation-mb,则实际分配内存大小为yarn.scheduler.minimum-allocation-mb+( total-yarn.scheduler.minimum-allocation-mb)取 yarn.scheduler.increment-allocation-mb的整数倍

假设:yarn.scheduler.minimum-allocation-mb=2G,yarn.scheduler.increment-allocation-mb=1G,--executor-memory 2G
executor所在container实际申请的内存=2G+1G=3G

AM所在executor实际申请内存=2G

所有总申请内存为5G