在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 on yarn内存分配
(1) 相关参数介绍
参考博文: http://blog.javachen.com/2015/06/09/memory-in-spark-on-yarn.html?utm_source=tuicool
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