You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark Executor内存Overhead耗尽原因及任务执行差异排查

解答

一、Spark YARN Executor内存Overhead的具体内容

spark.yarn.executor.memoryOverhead是为Executor进程的非堆内存开销预留的额度,这部分内存不包含在spark.executor.memory配置的JVM堆内存内,YARN会监控容器总内存(堆内存+Overhead)的使用情况,具体涵盖以下几类开销:

  • JVM原生内存开销:包括JVM代码缓存(存储JIT编译后的机器码)、垃圾回收器工作内存(如标记阶段的临时数据存储)、线程栈内存(单线程默认栈大小1MB,线程数量越多开销越大)、直接内存(NIO ByteBuffer等绕过JVM堆的内存分配)。
  • 第三方库与Spark组件的原生内存使用:即使JDBC驱动是纯托管代码,若驱动内部使用NIO直接内存、或依赖的序列化库(如Kryo)处理数据时用到原生内存,都会计入Overhead;此外Spark的Netty网络组件处理IO时也会占用直接内存。
  • 进程级系统开销:操作系统为Executor进程分配的页表、文件描述符关联内存等底层资源占用。
  • 瞬时内存波动:任务执行过程中的临时内存峰值,比如JDBC读取时的结果集缓存、数据序列化/反序列化的临时内存占用,这些峰值可能超出堆内存预估范围,需要Overhead来承接。

Spark默认Overhead取值为max(384MB, 0.1*spark.executor.memory),它是YARN容器总内存的组成部分,一旦容器物理内存使用(含所有上述开销)超过spark.executor.memory + spark.yarn.executor.memoryOverhead的总和,YARN就会触发容器杀死操作。

二、部分Executor执行同一任务失败、重试成功的原因

这种现象源于内存使用的随机性与节点资源差异,具体原因包括:

  • 节点资源竞争差异:不同YARN节点的系统负载不同,部分节点可能同时运行NodeManager、其他业务容器等进程,可用物理内存余量更少。当Executor调度到这类节点时,即使任务本身内存使用正常,也可能因节点整体内存紧张被YARN判定为超量使用而杀死;重试时任务可能被调度到资源更充足的节点,从而成功执行。
  • 任务执行的内存波动:同一查询在不同Executor上执行时,内存使用会存在瞬时波动——比如GC触发时机不同,某个Executor执行时恰好遇到GC的内存峰值;或JDBC读取结果集的加载顺序、数据分片的内存占用分布不同,导致瞬时内存超出容器限制。重试时这些随机因素发生变化,内存峰值未超过阈值,任务即可成功。
  • Executor状态差异:运行过一段时间的Executor可能存在堆内存碎片、残留临时对象,可用内存比新启动的Executor更少。重试时若调度到新启动的Executor,或原有Executor经过Full GC释放了足够内存,就能满足任务的内存需求。
  • YARN监控的瞬时误差:YARN通过操作系统的进程内存统计(如RSS)监控容器内存,存在一定延迟或瞬时误差。若某个时刻任务的内存峰值刚好被监控捕获,就会触发容器杀死;重试时该峰值未被捕获或峰值更低,任务得以完成。

额外优化建议

你的代码使用Scala并行集合在Driver端并行提交多个Spark Job,这种方式会导致多个Job同时抢占Executor资源,内存需求叠加后更容易触发YARN内存限制。建议改用Spark分布式执行框架处理查询:将查询列表转为RDD/DataFrame,利用Spark的分区并行执行每个查询的读取与写入,避免Driver端并行带来的资源竞争问题。


内容的提问来源于stack exchange,提问作者Alexey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:17:12