
点亮⭐️
https://github.com/apache/
点击蓝字 关注我们

导读

在数据平台的日常运行中,任务失败几乎是不可避免的。网络抖动、资源不足、下游依赖异常、代码 Bug……都可能导致调度任务执行失败。面对失败,很多团队通常依赖 自动重试、手动重跑或补数回填 来恢复数据。
但一个经常被忽视的问题是:
调度系统中的失败重试、手动重跑与补数回填,其语义其实完全不同。
如果理解不清,很容易导致 重复数据、数据错位甚至数据污染。本文将结合 Apache DolphinScheduler 的设计机制,深入解析调度系统中最常见但也最容易被误解的三种能力:失败重试、手动重跑与补数回填,并进一步探讨 调度系统中 “Exactly Once” 的真实含义。
失败重试 vs 手动重跑
在调度系统中,失败任务通常有两种恢复方式:
自动重试(Retry)
手动重跑(Rerun)
很多人认为两者只是触发方式不同,但实际上它们在 执行语义 上有本质差异。
01
自动重试:同一实例再次执行
在 Apache DolphinScheduler 中,每一次调度都会生成一个 Workflow Instance(流程实例),实例中包含多个 Task Instance(任务实例)。
当某个任务失败时,如果配置了 Retry Times,系统会在同一个任务实例下触发自动重试。
其特点是:
属于同一次工作流实例
保持相同的调度时间(Schedule Time)
依赖关系不会改变
仅重新执行失败任务
执行流程示意:

自动重试的设计目标是:
解决瞬时失败(Transient Failure)
例如:
在这种情况下,自动重试通常可以快速恢复任务。
02
手动重跑:创建新的实例
与自动重试不同,手动重跑会生成新的实例。
在 Apache DolphinScheduler 中,用户可以选择:
重跑失败节点
从当前节点开始重跑
从头重跑整个流程
这时系统会生成一个新的 Workflow Instance。
示意:

这意味着,两个实例 可能处理同一时间的数据,下游任务 可能重复写入数据。
如果任务不是 幂等(Idempotent) 的,就可能导致 重复数据问题。
补数与回填
在数据仓库场景中,补数(Backfill)是一项非常常见的操作。例如:
在 Apache DolphinScheduler 中,补数通常通过 Backfill Run 实现。
01
补数的本质:生成多个历史实例
假设一个任务是 每日调度。
补数区间:
2025-03-01 → 2025-03-05
系统会创建多个实例:
Instance (2025-03-01)Instance (2025-03-02)Instance (2025-03-03)Instance (2025-03-04)Instance (2025-03-05)
每个实例都有:
调度时间会被设置为历史时间。
02
补数关键:调度时间vs执行时间
在调度系统中,有两个非常重要的概念:
调度时间(Schedule Time)
数据逻辑时间
执行时间(Execution Time)
任务实际运行时间
例如:
Schedule Time : 2025-03-01Execution Time: 2025-03-10
如果 SQL 使用的是:
WHERE dt = ${schedule_time}补数是安全的。
但如果使用:
WHERE dt = today()
补数就会产生 错误数据。
这也是很多数据问题的根源。
调度系统中的Exactly Once
在流处理系统中,例如 Apache Flink,Exactly Once 通常意味着:
每条数据只被处理一次。
但在调度系统中,Exactly Once 的含义完全不同。
调度系统并不能保证任务不会被重复执行,也无法保证数据不会被重复写入。这是因为自动重试可能重复执行,手动重跑可能重复执行,以及补数会重复执行历史逻辑。
因此,调度系统中的 Exactly Once 更接近于:
同一个调度时间只生成一个逻辑实例。
但任务本身仍然可能执行多次。
因此真正的 Exactly Once 需要 任务逻辑保证幂等。
常见实现方式包括:
01
覆盖写入
INSERT OVERWRITE TABLE
02
基于分区写入
partition dt='${schedule_time}'03
去重写入
MERGE INTO
常见误用场景
很多数据事故其实都来自于对调度语义的误解。
01
使用当前时间作为数据日期
错误示例:
dt = today()
正确方式:
dt = ${schedule_time}
02
非幂等写入
例如:
INSERT INTO table
如果任务重跑:
数据会重复
03
手动重跑整个流程
很多用户习惯:
失败 → 从头重跑
但实际上更安全的方式是:
只重跑失败节点
最佳实践建议
结合 Apache DolphinScheduler 的使用经验,可以总结出几个重要实践:
01
任务必须设计为幂等
所有任务都应该允许:
重复执行
不会影响数据正确性。
02
数据逻辑必须基于调度时间
避免使用:
now()
today()
统一使用:
${schedule_time}
03
合理使用重试策略
建议配置:
Retry Times: 1~3
Retry Interval: 1~5 min
避免无限重试。
04
补数要控制并发
补数区间过大时:
一次性生成大量实例
可能导致:
建议:
分批补数
结语
在数据平台中,调度系统往往被认为只是“任务触发器”。但实际上,它承担着 时间管理、依赖控制和故障恢复 的核心职责。
通过理解 失败重试、手动重跑与补数回填 的真实语义,我们才能真正构建 稳定、可靠的数据生产系统。
像 Apache DolphinScheduler 这样的现代调度系统,已经提供了非常完善的机制。但最终决定数据质量的,仍然是:
正确理解调度语义 + 设计幂等的数据任务。
只有这样,数据平台才能在面对失败时依然保持 可恢复、可追溯、可重建。
END

用户案例

迁移实战

最新发版消息

加入社区
关注社区的方式有很多:
同样地,参与Apache DolphinScheduler 有非常多的参与贡献的方式,主要分为代码方式和非代码方式两种。
非代码方式包括:
完善文档、翻译文档;翻译技术性、实践性文章;投稿实践性、原理性文章;成为布道师;社区管理、答疑;会议分享;测试反馈;用户反馈等。
代码方式包括:
查找Bug;编写修复代码;开发新功能;提交代码贡献;参与代码审查等。


你的好友秀秀子拍了拍你
并请你帮她点一下“分享”
