资源配置调优
1、Executor 内存与核数:spark.executor.memory 建议为 4g~16g,spark.executor.cores 建议 2~5,单个 Executor 核数过多会加剧内存争抢;
2、Executor 数量:通过 --num-executors 或 spark.executor.instances 指定,需结合 YARN 队列资源评估,避免占用过多队列资源或长时间排队;
3、Driver 内存:有 collect、广播大变量、缓存元数据等行为时需调大 spark.driver.memory,否则可能触发 OOM;
4、内存模型:spark.memory.fraction(默认 0.6)划分统一内存(执行+存储),频繁缓存 RDD 或 Shuffle 溢写严重时可结合 spark.memory.storageFraction 调整;
注意
spark.memory.fraction 与 spark.memory.storageFraction 属于底层内存模型参数,一般保持默认值,不建议直接修改;内存不足时优先调大 spark.executor.memory。
并行度调优
1、分区数建议为总核心数的 2~3 倍,使任务调度有弹性;
2、spark.sql.shuffle.partitions 默认 200,大表 Join/聚合需适当调大,小数据量场景可调小以减少小任务开销;
3、AQE(spark.sql.adaptive.enabled,默认开启)会在运行时自动合并过小的 Shuffle 分区,无需为小数据量手工调参;
4、RDD 算子分区数可通过 repartition/coalesce 调整,coalesce 收缩分区不触发 Shuffle,优先使用。
数据倾斜与Shuffle 调优
1、开启 AQE 倾斜 Join 优化(spark.sql.adaptive.skewJoin.enabled,默认开启),自动拆分倾斜分区;
2、大表 Join 小表优先广播(broadcast),避免 Shuffle:小表大小需小于 spark.sql.autoBroadcastJoinThreshold(默认 10MB);
3、聚合类倾斜可先对 key 加盐打散再二次聚合;
4、Shuffle 相关参数:spark.shuffle.file.buffer(默认 32k)与 spark.reducer.maxSizeInFlight(默认 48m)适当调大可减少溢写文件数与拉取次数;
5、序列化:shuffle 与缓存数据量大时配置 spark.serializer 为 KryoSerializer,并注册自定义类,可显著降低内存与网络开销。
推测执行注意事项
1、推测执行(spark.speculation,默认 false)对慢任务启动备份 Task 实例,以最先完成的实例结果为准,可缓解个别节点故障导致的长尾;
2、推测执行仅适用于幂等计算(如读取分析类作业),对有副作用的写操作(如写出文件、写数据库)会导致重复写入;
3、与 Hudi 配合使用时必须保持关闭:Hudi 1.2.0 默认开启写保护(hoodie.block.writes.on.speculative.execution 默认 true),检测到 spark.speculation=true 时写入直接抛异常报错,需关闭推测执行或明确自行承担风险后才可写入;
4、与 Hudi 配合使用时还需关闭列默认值特性:spark.sql.defaultColumn.enabled(Spark 3.4 默认 true)需显式设置为 false,否则 INSERT INTO 指定列时会报 "hudi not support specified cols when enable default columns" 错误;Spark 3.4 桥接层(HoodieSpark34CatalystPlanUtils)已修复相关兼容问题,但仍建议显式关闭以保证行为一致。
SQL 调优建议
1、使用 DataFrame/Dataset API 与 Spark SQL 代替 RDD API,充分利用 Catalyst 优化(谓词下推、列裁剪、Join 策略选择);
2、避免 select *,只取需要的列,减少 IO 与内存占用;
3、合理使用缓存:对多次使用的中间结果调用 cache()/persist(),用完及时 unpersist();
4、广播变量:Driver 端大对象使用广播而非闭包引用,避免 Task 序列化膨胀;
5、通过 Spark Web UI 的 Stages/SQL 页签定位长尾 Stage 与 Task,结合 Summary Metrics 分析倾斜与慢任务。