Spark从大节点转多小节点横向扩展时内存溢出问题求助
我之前帮团队处理过几乎一模一样的场景——总资源不变但拆分executor后出现YARN内存超限,核心问题在于小executor的内存模型和资源分配逻辑和大节点有本质差异,总资源匹配不代表每个小节点能承载对应工作。下面是我总结的排查步骤和优化技巧:
一、先解决当前的内存溢出问题
你的报错Container killed by YARN for exceeding memory limits. 8.8 GB of 8.8 GB physical memory used已经给出明确线索:
YARN容器的总内存 = Executor内存 + YARN内存Overhead,默认Overhead是Executor内存的10%(8G*10%=0.8G,刚好凑成8.8G)。小executor的非堆内存(比如Netty通信、序列化缓存、JVM元数据)占比相对大节点更高,默认的10%Overhead完全不够用。
调整YARN内存Overhead:直接设置固定值而非比例,比如:
spark.yarn.executor.memoryOverhead=2048 # 2GB,根据实际情况可调整到1.5-3GB这样容器总内存变为8G+2G=10G,避免YARN因物理内存超限kill容器。
优化JVM垃圾回收配置:小executor堆内存小,GC压力更大,容易出现内存碎片或OOM,建议切换到G1GC:
spark.executor.extraJavaOptions="-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=70"G1GC能更高效地处理堆内存碎片,减少Full GC的概率。
二、核心扩展优化技巧
1. 精细化内存分配
Spark Executor内存分为Execution(计算内存)、**Storage(缓存内存)和Other(其他内存)**三部分,默认比例可能不适合小executor:
- 如果你的任务以shuffle计算为主,可提高Execution内存占比:
spark.memory.fraction=0.8 # 让Execution+Storage占堆内存的80%(默认0.6) spark.memory.storageFraction=0.3 # Storage占Execution+Storage的30%,剩下70%给Execution - 如果有大量缓存数据,可适当提高
storageFraction,但要保证计算内存足够。
2. 确保分区“真的变小”
你已经把分区数增加到3倍,但要警惕数据倾斜导致部分分区仍然过大:
- 检查分区大小分布:
// 抽样查看每个分区的数据量 df.sample(0.05).rdd.mapPartitions(iter => Iterator(iter.size)).collect() - 如果发现热点分区(某几个分区数据量是其他的数倍),需要解决数据倾斜:比如给热点Key加盐拆分、过滤异常大Key、或者用广播Join替代Shuffle Join。
3. 同步调整并行度配置
分区数只是基础,还要同步调整shuffle和RDD的并行度:
- 调整SQL Shuffle并行度:默认200,建议设置为总核心数的2-3倍(你现在总核心是12*4=48,可设为100-150):
spark.sql.shuffle.partitions=120 - 调整RDD默认并行度:
让每个小executor的核心都能均匀分配到任务,避免单核心负载过高。spark.default.parallelism=96 # 一般设为总核心数的2倍
4. 减少内存占用的代码级优化
小executor对内存更敏感,需要从代码层面压缩内存开销:
- 改用Kryo序列化:比Java序列化更紧凑,减少内存和网络传输开销:
spark.serializer=org.apache.spark.serializer.KryoSerializer spark.kryo.registrationRequired=true # 注册自定义类进一步优化 - 优化广播变量:如果广播了大数据集,每个executor都会缓存一份,小executor内存占比极高。尽量只广播必要数据,或者对广播数据做过滤/压缩。
- 清理不必要的缓存:检查代码中是否有
persist()/cache()的数据集不再使用,及时用unpersist()释放内存。
三、验证与调优步骤
建议按以下顺序逐步验证:
- 先调整YARN Overhead和JVM参数,解决当前OOM问题;
- 检查分区分布,解决数据倾斜;
- 调整并行度和内存分配比例;
- 最后做代码级的序列化和缓存优化。
内容的提问来源于stack exchange,提问作者irbull

