本文档综合了 Spark 工程中常见的性能瓶颈和优化技巧,分为七大调优方向,适用于 PySpark 和 Scala Spark 场景,包括资源配置、并行度、缓存、垃圾回收、UDF 性能、Shuffle 优化和作业结构管控等。
一、资源配置调优
目标
合理分配 executor 和 JVM 内存,避免 OOM 和 GC 过高导致性能下降或 executor 被 YARN Kill。
优化策略
参数 | 推荐配置 | 说明 |
---|---|---|
--executor-memory |
8G ~ 20G | JVM 堆内存,过大易导致 Full GC |
--executor-cores |
2 ~ 5 | 避免超过带条数导致 GC |
spark.executor.memoryOverhead |
至少 2G(PySpark 推荐为 4G 或更高) | off-heap 内存,包括 Python UDF/缓冲区/数据缓存 |
--num-executors |
根据总核数计算 | = 总CPU核数 / 每executor核数 |
示例
--executor-memory 16G \
--executor-cores 4 \
--conf spark.executor.memoryOverhead=4G \
--num-executors 50
二、数据分区和并行度
目标
避免 task 单次处理数据过多或过少,导致 GC 或分布失衡,强化应用的并行能力。
优化策略
-
初始读取后使用
repartition(n)
指定分区 -
调整
spark.sql.shuffle.partitions
(默认 200) -
结果写出前使用
coalesce(n)
减少小文件df = df.repartition(200)
spark.conf.set("spark.sql.shuffle.partitions", "400")
df.coalesce(100).write.parquet("...")
三、缓存优化
目标
提高数据重复读取时性能,避免多次进程计算。
优化策略
-
使用
persist()
替代cache()
-
指定缓存级别:
MEMORY_AND_DISK_SER
节省内存 -
后续不使用时应该
unpersist()
from pyspark import StorageLevel
df.persist(StorageLevel.MEMORY_AND_DISK_SER)
...
df.unpersist()
四、垃圾回收 (GC) 优化
目标
降低 GC 时间,避免 JVM 停顿,提高作业稳定性。
优化策略
-
JVM 堆内存 <= 20G
-
推荐使用 G1GC
-
启用 GC 日志分析
--conf spark.executor.extraJavaOptions="-XX:+UseG1GC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
五、UDF 代码和逻辑优化
目标
减少 JVM 和 Python 之间的序列化或处理费,提高运行效率。
优化策略
-
优先考虑 Spark SQL 表达式或 built-in 函数
-
用 pandas UDF 替换 Python UDF
-
避免 collect()/groupByKey()
@pandas_udf(StringType(), functionType="PANDAS_UDF")
def clean(col: pd.Series) -> pd.Series:
return col.str.lower().str.strip()df = df.withColumn("cleaned", clean("name"))
六、Shuffle 性能优化
目标
降低 shuffle 输入输出 IO 和缓冲压力,避免倦缓/磁盘 spill,提高性能。
优化策略
-
避免 groupByKey,优先 reduceByKey 或 aggregateByKey
-
启用 shuffle 压缩、spill 压缩
-
适应场景使用 Broadcast Join / Sort-Merge Join
-
解决数据倾斜:Salting 或 AQE
示例配置
--conf spark.shuffle.compress=true \
--conf spark.shuffle.spill.compress=true \
--conf spark.shuffle.file.buffer=64k \
--conf spark.sql.autoBroadcastJoinThreshold=10MB \
--conf spark.sql.adaptive.enabled=true
七、作业结构和任务管理
目标
控制 DAG 深度,避免特殊大 task 倾斜,提升较均衡执行效率。
优化策略
-
较复杂的 DAG 作业分时 checkpoint/cache
-
推荐使用 AQE 展现时动性分区和 join 选择
-
避免大幅 broadcast join (大于 10MB)
spark.conf.set("spark.sql.adaptive.enabled", "true")
总结:Spark 调优七步法(记忆词:资-分-存-收-码-洗-控)
分类 | 内容 |
---|---|
1. 资源配置 | 内存/核数/超越内存配置 |
2. 分区并行度 | repartition / shuffle 分区 |
3. 数据缓存 | persist 级别 / 释放时机 |
4. GC 优化 | G1GC / JVM 堆 / GC 日志 |
5. UDF 逻辑 | pandas UDF / Spark SQL 替代 |
6. Shuffle 优化 | join 类型 / 倾斜解决方案 |
7. 作业控制 | AQE / checkpoint / 分步执行 |