堆内存 (on-heap memory) 即为 JVM 内存. 机器内存中不属于堆内存的部分即为堆外内存 (off-heap memory). 堆外内存主要用于程序的共享库, Perm Space, 线程 Stack 和一些 Memory mapping 等, 或者类 C 方式 allocate object, 在 Spark 中可以从逻辑上分成两种: 一种是 DirectMemory, 一种是 JVM Overhead.
Spark 任务发生 OOM 要分情况讨论, 视其出现的位置判断如何优化.
堆内存 OOM
Spark 框架主要有两处消耗 on-heap memory 的地方, Spark 内部将其分成 Storage 和 Execution 2 个区:
(1) Storage: persist / cache / sc.broadcast 等
(2) Execution: 主要用于 Shuffle 阶段, read shuffle/write shuffle 阶段需要开 buffer 来做一些 merge 操作或者防止 shuffle 数据放内存原地爆炸. 一般涉及的操作: XXXXByKey(reduceByKey,combineByKey等)/coGroup/join类等.
堆内存涉及到的参数:
参数 | 描述 | 默认值 |
---|---|---|
spark.memory.fraction | 存 RDD/broadcast 等 Block 的和 Shuffle 数据的 memory 比例 | 0.55 |
spark.memory.storageFraction | spark.memory.fraction 中用来存 Block 的 memory 比例, 只是一个基准值, 非绝对值 | 0.5 |
OOM 原因:
- Driver 端创建大对象或者 collect() 大对象 => Driver 堆内存 OOM
- 数据倾斜 => Executor 堆内存 OOM
(1) 截断 / 过滤
(2) 对 key 做切分, keyA 变为 keyA_1, keyA_2, ...
(3) 配置升级, 提高 exeutor-memory, 降低 spark.memory.fraction (至少为 0.1) - Executor 端创建大对象 => Executor 堆内存 OOM
堆外内存 OOM
参数 | 描述 | 默认值 |
---|---|---|
spark.yarn.executor.jvmMemoryOverhead | off heap 内存控制 | max(0.1 * executorMemory, 384MB) |
spark.yarn.executor.directMemoryOverhead | Direct Memory 的控制参数 | 256MB |
spark.yarn.driver.jvmMemoryOverhead | 同 Executor | |
spark.yarn.driver.directMemoryOverhead | 同 Executor | |
spark.yarn.executor.memoryOverhead | 统筹参数, 如果设置了该值 m, 会自动按比例分配 off heap 给 jvmOverhead 和 directMemory, 分配比例为 jvmOverhead = max(0.1 * executorMemory, 384MB), directMemoryOverhead = m - jvmOverhead | 无 |
spark.yarn.driver.memoryOverhead | 同 Executor |
spark.yarn.executor.directMemoryOverhead =
{ if (存在 memory level or disk level 的 block) then 第 1 点的 size else 0 }
+ { if (shuffle 阶段抛出 Direct OOM) then 第 2 点的 size else 0 }
+ { if (存在 disk level 的 block) then 第 3 点的 192MB else 0 }
+ { if (存在其他框架的) then 其他框架的 size else 0 }
+ 256MB
spark.yarn.executor.jvmOverhead =
{ if (存在 disk level 的 block) then 第 4 点的 size else 0 }
+ { if (存在其他框架的) then 其他框架的 size else 0 }
+ max(executor-memory * 0.1, 384)
// 如果没有 Executor 表现为堆外内存使用超出, 则不需要手动调整.