订阅更新

Spark作业突然OOM了,你怎么排查和解决?

Spark手册 第 1 题 约 5 分钟读完

本文目录
  1. 先说结论
  2. Driver端 OOM(3种常见场景)
  3. Executor端 OOM(最常见)
  4. Spark内存模型一张图
  5. 实战排查流程
  6. 总结

先说结论

Spark OOM发生在两个地方:Driver端和Executor端。排查第一步是看报错日志确定是哪一端的OOM,然后对症下药。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

OOM是Spark生产环境里最常见的报错,没有之一。很多人一看到OOM就说“加内存”,但这只是头痛医头。面试官想听的是你能不能系统地分析原因并对症下药。今天把排查OOM的完整思路和最常见的4种场景讲清楚。

Driver端 OOM(3种常见场景)

场景一:collect()拉取太多数据到Driver

这是最常见的Driver OOM原因。我在出海硬件公司遇到过:有个同事写了df.collect()想在Driver端做一些处理,结果这个DataFrame有500万行,Driver直接爆了。

// ✖ 危险:把全部数据拉到Driver
val allData = df.collect()  // 500万行全部拉到Driver内存
 
// ✔ 安全:用take()或limit()只拉少量数据
val sample = df.take(100)
 
// ✔ 或者把逻辑放在Executor端执行
df.foreachPartition(partition => { /* 在Executor端处理 */ })

场景二:广播变量太大

广播一张大的查找表到所有Executor,Driver要先拉取这张表的全部数据再广播出去。如果查找表超过几百MB,Driver就可能OOM。解决方案:确保只广播小表(一般不超过200MB)。

场景三:太多小文件生成太多分区

读取一个有几万个小文件的目录,每个文件生成一个分区,Driver要维护几万个Task的元数据,内存不够。解决方案:先coalesce()减少分区数,或者加大Driver内存。

Executor端 OOM(最常见)

Executor端 OOM的核心原因是:单个Task处理的数据量超过了分配给它的内存。两种典型场景:

数据倾斜: 某个Key的数据量远超其他Key,处理这个Key的Task内存爆了。这个是最常见的Executor OOM原因,后面第3篇专门讲。

Shuffle数据量太大: reduceByKey、groupByKey等操作把大量数据拉到同一个Executor。解决方案:增加分区数(spark.sql.shuffle.partitions),让每个Task处理更少的数据。

// 调整内存相关配置
spark.conf.set("spark.executor.memory", "8g")
spark.conf.set("spark.executor.memoryOverhead", "2g")  // GC和堆外内存
spark.conf.set("spark.sql.shuffle.partitions", "400")  // 增加并行度
 
// 设置内存分配比例
spark.conf.set("spark.memory.fraction", "0.6")      // 统一内存占比60%
spark.conf.set("spark.memory.storageFraction", "0.5") // 其中存储卐50%

Spark内存模型一张图

区域占比用途
Reserved Memory固定300MBSpark内部对象
User Memoryheap × (1 - fraction)用户代码的数据结构、UDF中的对象
Unified Memoryheap × fractionExecution(Shuffle/Sort)+ Storage(Cache)动态分配

Spark 2.x之后用统一内存管理,Execution和Storage可以互相借用。当Execution内存不够时可以将Storage内存挤出去(抌cache数据刷到磁盘),但反过来不行——这就是为什么Shuffle内存不够会直接OOM而不是溢出到磁盘。

实战排查流程

我在出海硬件公司迁移到Databricks之后,建立了一套OOM排查流程:

1. 看YARN/Spark UI的报错日志,确认是Driver还是Executor

2. Driver OOM → 搜索代码里的collect()/broadcast() → 改为分布式处理

3. Executor OOM → 看Spark UI的Stage详情,找到处理数据量最大的Task

4. 如果某个Task的Shuffle Read远超其他Task → 数据倾斜,用加盐打散解决

5. 如果所有Task都差不多大 → 单线OOM,加内存或增加分区数

总结

OOM排查第一步是分清Driver还是Executor。Driver OOM通常是collect()/broadcast()导致,Executor OOM通常是数据倾斜或分区数太少。加内存是最后的手段,不是第一步。面试时能说清楚内存模型和排查流程,再加一个实战案例,就很完整。

下一篇聊一个每个数据开发都会遇到的场景:两张大表Join跑了2小时,你怎么优化?

你们遇到过最难排查的OOM是什么场景?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器