本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Spark 内存调优以及 JVM 调优
目前Spark使用的内存管理模型有两个,分别是:
- StaticMemoryManager
- UnifiedMemoryManager
而StaticMemoryManager是1.6之前的版本使用的内存管理模型.UnifiedMemoryManager是1.6之后使用的内存管理模型. 在SparkEvn中,通过spark.memory.useLegacyMode参数来进行内存管理模型的配置,默认false,即默认使用UnifiedMemoryManager.
val useLegacyMemoryManager = conf.getBoolean("spark.memory.useLegacyMode", false)
val memoryManager: MemoryManager =
if (useLegacyMemoryManager) {
new StaticMemoryManager(conf, numUsableCores)
} else {
UnifiedMemoryManager(conf, numUsableCores)
}
StaticMemoryManager
StaticMemoryManager模式下,分配给Spark的内存主要分为3部分.
- Storage 部分,主要用于存储 RDD 缓存的数据和 broadcast 广播的数据,这部分内存占给定 spark 内存的60%.其中这部分的10%用于Storage 内存的预留内存.剩下的90%用于存储.而剩下的90%又划分出20%的大小单独用于缓存 iterator 形式的 Block 数据,即 unroll 部分.
- Shuffle 部分,这部分内存占给定 spark 内存的20%,主要用于存储 Shuffle 过程中的中间数据(或者可以说用于 Task 任务的计算),这部分也有20%的大小用于预留内存,80%的大小用于真正的计算用.
- Other 部分,这部分内存占给定 spark 内存的20%,用于存储用户定义的数据结构或者 spark 内部的元数据.
UnifiedMemoryManager
UnifiedMemoryManager模式下,spark 内存主要分为三块:
- Storage&Execution,其中 Storage 主要用于存储 RDD 缓存的数据和 broadcast 广播的数据.Execution主要用于 Task 的计算(存储 shuffle 中间数据).Storage 和 Execution 大小默认比例为50%,但是,这是个软边界限制,也即当一方不足时,可以申请向另一方借用.Storage&Execution由spark.memory.fraction参数控制,默认60%.Storage与 Execution 占比由spark.memory.storageFraction参数控制,默认各占50%.
- User Memory,用户内存区域,主要用于存储 spark 的 RDD 转换过程中使用的数据结构,官网上说的是 Spark完全没有考虑你在那里做什么以及你是否尊重这个边界.这部分内存的大小就是 spark 分配给用于存储和计算的内存之外的内存.默认为(1-spark.memory.fraction)
- Reserved Memory,系统保留内存,不在任何生产环境下使用.这块区域的大小是默认值300M,不能更改. spark 内存调优参数:
| 参数 | 默认值 | 作用 |
|---|---|---|
| spark.memory.useLegacyMode | false | 选用内存管理模式,默认为 false,即默认使用 UnifiedMemoryManager,为 true 时,使用StaticMemoryManager |
| spark.storage.safetyFraction | 0.9 | StaticMemoryManager 模式下,实际用于存储的安全系数 |
| spark.storage.memoryFraction | 0.6 | StaticMemoryManager 模式下,用于缓存 RDD 数据以及 broadcast 数据,实际大小为systemMaxMemory*0.6*0.9*(1-unrollFraction) |
| spark.shuffle.safetyFraction | 0.8 | StaticMemoryManager 模式下实际用于计算的安全系数 |
| spark.shuffle.memoryFraction | 0.2 | StaticMemoryManager 模式下,用于存储 shuffle 中间数据(task 计算) 实际大小为 systemMaxMemory * 0.2*0.8 |
| spark.storage.unrollFraction | 0.2 | StaticMemoryManager 模式下,unroll 内存所占比例,主要用于缓存 iterator 形式的 Block 数据,实际大小为systemMaxMemory*0.6*0.9*unrollFraction |
| spark.memory.fraction | 0.6 | 控制UnifiedMemoryManager模式下,用于存储和计算的总内存,实际大小为(systemMemory-300M)*0.6 |
| spark.memory.storageFraction | 0.5 | 控制UnifiedMemoryManager模式下,用于存储和计算的内存占比,实际大小为(systemMemory-300M)*0.6*0.5.这是个软边界,当一方不足时,可以向另一方借用,比如 storage 不足时,可以向 execution 借用 |
| spark.memory.offHeap.enabled | false | 是否使用堆外内存,默认是不使用堆外内存的,当开启的时候,需要指定堆外内存的大小并且大于0 |
| spark.memory.offHeap.size | 0 | 堆外内存大小,当启用堆外内存时,这个参数的值需要大于0,单位字节 |
| spark.storage.replication.proactive | false | 默认是不启用该参数的,如果启用,则会在Executor故障丢失了rdd时,使用 RDD 的副本进行恢复,而不用重新开始计算. 如果开启,将会使用额外的存储空间. |
| spark.cleaner.periodicGC.interval | 30min | 控制触发垃圾回收的频率 |
| spark.cleaner.referenceTracking | true | 是否启用上下文清理.清理那些超出应用范围的 RDD,Shuffle 对应的 map 任务状态,Shuffle 元数据,Broadcast 对应以及 RDD 的 Checkpoint 数据 |
| spark.cleaner.referenceTracking.blocking | true | 清理非Shuffle的其它数据是否是阻塞式的 |
| spark.cleaner.referenceTracking.blocking.shuffle | false | 清理Shuffle数据是否是阻塞式的,清理MapOutputTracker中指定ShuffleId对应的map任务状态和ShuffleManager中注册的ShuffleId对应的Shuffle元数据。 |
| spark.driver.extraJavaOptions | - | 用于设置 driver 端的 jvm 参数 |
| spark.executor.extraJavaOptions | - | 用于设置 executor 端的 jvm 参数 |