Spark的推测执行(Speculative Execution)
Spark 的推测执行(Speculative Execution) 是一种用于处理“长尾任务”(Stragglers)的容错与优化机制。
简单来说,当 Spark 发现某个任务(Task)的运行速度远慢于同阶段的其他任务时,它会“推测”该任务所在的节点可能存在硬件故障或高负载,从而在另一个节点上启动该任务的副本。这两个任务谁先运行完,就以谁的结果为准,并杀掉另一个未完成的任务。
以下是关于 Spark 推测执行的详细解析:
1. 为什么需要推测执行?(背景)
在分布式计算中,一个 Stage 的完成时间取决于最慢的那个 Task(木桶效应)。即便 99% 的任务在 1 分钟内完成,如果剩下的 1% 需要 10 分钟,整个作业也需要 10 分钟。
导致任务变慢的原因通常有:
- 硬件异构:集群中某些机器性能较差(CPU 弱、磁盘老化)。
- 网络拥堵:特定节点网络 I/O 慢。
- 高负载/GC:某节点上运行了其他高资源消耗程序,或者正在进行长时间的 Full GC。
推测执行的目的就是牺牲少量的计算资源,换取整体作业执行时间的缩短。
2. 工作原理
Spark Driver 会定期检查所有正在运行的任务的进度。推测执行的触发流程如下:
- 监控:Driver 收集 Stage 中所有 Task 的运行指标。
- 判断阈值:当满足以下条件时,任务被标记为“可推测”(Speculatable):
- 该 Stage 中已有一定比例(如 75%)的任务成功完成。
- 该任务正在运行,且运行时间超过了该 Stage 所有成功任务运行时间中位数的特定倍数(如 1.5 倍)。
- 启动副本:Spark 会在不同的 Executor(如果可能的话,不同的物理节点)上启动该任务的一个副本。
- 竞速:原任务和副本任务同时运行。
- 完成:
- 胜者:第一个完成的任务会将结果 Commit(提交)。
- 败者:Driver 会自动 Kill 掉另一个还在运行的任务。
3. 核心配置参数
Spark 默认是关闭推测执行的。要在 spark-defaults.conf 或提交任务时开启,需配置以下参数:
| 参数名 | 默认值 | 说明 |
|---|---|---|
spark.speculation |
false |
是否开启推测执行。设置为 true 开启。 |
spark.speculation.interval |
100ms |
Driver 检查是否需要推测执行的时间间隔。 |
spark.speculation.multiplier |
1.5 |
慢任务判定倍数。如果任务运行时间 > 中位数 * 1.5,则视为慢任务。 |
spark.speculation.quantile |
0.75 |
启动推测执行的进度阈值。表示 Stage 中必须有 75% 的任务完成后,才开始检测慢任务。 |
4. 潜在风险与何时应该关闭(重要)
虽然推测执行看起来很美好,但在实际生产环境中,很多时候建议关闭,或者需要非常谨慎地使用。原因如下:
A. 数据倾斜 (Data Skew) - 最常见的问题
如果某个 Task 慢是因为它处理的数据量远大于其他 Task(数据倾斜),而不是因为机器慢,那么推测执行毫无用处。
- 后果:启动的副本任务处理同样巨量的数据,依然会很慢。这不仅不能加速,反而浪费了宝贵的集群资源,甚至可能导致集群资源紧张引发更多问题。
- 解决:遇到这种情况,应先解决数据倾斜问题(如加盐、重分区),而不是依赖推测执行。
B. 非幂等操作 (Non-idempotent Operations)
如果你的 Spark 任务涉及对外部系统的写操作(如向 MySQL 插入数据、调用外部 API),且该操作不是幂等的(Idempotent),开启推测执行会导致数据重复。
- 场景:Task A 插入了一条数据,还没报告完成;副本 Task B 也插入了同样的数据。最终数据库里会有两条。
- 注意:写 HDFS 通常是安全的,因为 Spark 的 OutputCommitter 会处理临时文件重命名,确保只有一个文件生效。但写数据库或非事务性存储时要格外小心。
C. 资源紧张
如果集群资源本身就已经非常紧张(队列满了),开启推测执行会抢占正常任务的资源,导致整体调度更慢。
5. 总结:什么时候使用?
建议开启的场景:
- 任务逻辑简单,主要是计算密集型或 I/O 密集型。
- 数据分布均匀(无明显数据倾斜)。
- 集群硬件老化严重,或者处于公有云环境(虚拟化导致的性能波动大)。
- 操作是幂等的(如纯计算、写 HDFS/Hive/S3)。
建议关闭的场景:
- 明确存在严重的数据倾斜。
- 任务包含非幂等的外部写操作(如
INSERT INTO关系型数据库且无主键去重)。 - 集群资源极其紧张。
最佳实践建议
在生产环境中,通常默认关闭推测执行。只有在观察到作业经常因为个别 Task 卡顿而导致整体延迟,且排除了数据倾斜问题后,才针对特定的作业开启该功能。