一、资源配置优化:Executor内存的"黄金分割"
1. 堆内内存:避免"过大或过小"的平衡术
核心公式:
executor.memory = 单Task内存需求 × executor.cores × 安全系数(1.5)
案例 :处理100GB数据,每个Task处理1GB数据,每个Executor分配4核(4个Task并行)
→ executor.memory = 1GB × 4 × 1.5 = 6GB
常见陷阱:
- 内存过小:
executor.memory=2G+executor.cores=4→ 每个Task仅500MB内存,处理1GB数据直接OOM; - 内存过大:
executor.memory=32G→ JVM GC时间过长(超过10秒),反而拖慢任务。
2. 堆外内存:被忽略的"救命稻草"
场景 :Shuffle过程中报"Cannot allocate direct buffer",这是堆外内存不足的典型症状。
解决方案:
bash
--conf spark.executor.memoryOverhead=4G # 堆外内存设置为堆内内存的50%-100%
原理:堆外内存用于存储Shuffle临时数据、NIO缓冲区,不经过JVM GC,对大Shuffle任务至关重要。
3. CPU核心配置:2-4核的"甜蜜点"
最佳实践 :executor.cores=2-4 (避免超过5核)
-
核数过少(如1核):并行度不足,资源利用率低;
-
核数过多(如8核):Task间内存竞争激烈,易导致单个Task内存不足。
二、分区策略优化:让数据"均匀起舞"
1. 并行度设置:总核数的2-3倍法则
关键参数:
spark.default.parallelism(RDD):集群总核数 × 2-3
→ 例:50个Executor × 4核 = 200核 → 并行度设为400-600spark.sql.shuffle.partitions(Spark SQL):默认200,数据量大时调至500-1000
效果:单分区数据量从2GB降至200MB,内存压力骤减。
2. 小文件合并:coalesce vs repartition
场景 :HDFS存在大量小文件(每个10MB以下),导致RDD分区数过多(>10000),Task数量爆炸引发OOM。
解决方案:
scala
// 合并小分区(无Shuffle,效率高) val mergedRDD = rdd.coalesce(100) // 从10000分区合并到100分区 // 数据倾斜时重分区(有Shuffle,均匀性好) val balancedRDD = rdd.repartition(200) // 随机打散数据
3. 数据倾斜处理:从"找到倾斜"到"解决倾斜"
步骤1:定位倾斜Key
scala
// 抽样10%数据,统计Key分布 val sample = rdd.sample(false, 0.1).countByKey() sample.foreach { case (key, count) => if (count > totalCount * 0.1) println(s"倾斜Key: $key, 数量: $count") }
步骤2:三大解决方案
| 倾斜类型 | 解决方案 | 适用场景 |
|---|---|---|
| 高频Key倾斜 | 加盐法(key + "_" + rand(10)) |
Key集中(如某Key占比30%) |
| 大表Join小表 | 广播小表(broadcast join) |
小表数据量<100MB |
| 全局聚合倾斜 | 两阶段聚合(先局部聚合,再全局聚合) | groupByKey导致的倾斜 |
三、监控与调优:用Spark UI"透视"OOM根源
1. 内存问题诊断
- Executors页面 :关注
Memory UsedvsMemory Total,若使用率长期>90%,需增加内存; - Stages页面 :查看
Shuffle Read Size,单个Task读取数据>1GB易OOM,需提高并行度。
2. 数据倾斜诊断
-
Task Metrics :查看每个Task的
Input Size和Shuffle Read Size,若最大/最小差异>10倍,存在倾斜; -
示例:某Stage中99个Task处理100MB数据,1个Task处理10GB数据 → 明显的Key倾斜。
四、避坑总结:Spark OOM调优 checklist
| 场景 | 关键操作 |
|---|---|
| 内存溢出(堆内) | 调大executor.memory ,降低executor.cores |
| 内存溢出(堆外) | 调大executor.memoryOverhead |
| Shuffle数据过大 | 提高spark.sql.shuffle.partitions |
| 数据倾斜 | 加盐法/广播Join/两阶段聚合 |