跳到主要内容

分布式任务调度

分布式任务调度按计划创建任务,并协调执行与恢复。本文负责实例标识、分片、租约、检查点和补跑。

1. 面试核心​

先记住这几条,再读正文
  • 任务实例。 任务实例以任务名和计划时间形成稳定 ID,重复触发读取同一记录。卡 · 综合题
  • 分片领取。 分片通过原子领取获得租约,失效后允许其他执行器接管。
  • 过期执行器。 fencing token 需要在资源写入端校验,才能拒绝过期执行器。卡 · 租约与所有者
  • 恢复进度。 检查点只推进已可靠完成的范围,业务写入需原子提交或幂等。
  • 启动与运行期限。 startingDeadlineSeconds 限制补调窗口,activeDeadlineSeconds 限制 Job 运行时间。卡 · 重试与补跑

2. 调度时间与执行时间​

调度器在计划时间创建实例,执行器稍后领取并运行。排队和故障恢复会让实际开始时间晚于计划时间。

Kubernetes CronJob 是近似调度。控制器故障等场景会造成重复创建或漏调。因此业务需接受同一计划的重复执行,并监控漏掉的实例。

3. 任务实例 ID​

任务名与计划时间共同标识一次逻辑执行:

daily-settlement:2026-08-30T00:00:00+08:00

数据库对实例 ID 建立唯一约束。重复触发读取已有状态,再决定等待、继续或返回结果。唯一实例记录负责去重创建,业务效果仍需幂等约束。

实例记录保存计划时间、状态、尝试次数和执行者。租约、分片进度、错误与结果也应可恢复。

4. 重叠执行策略​

concurrencyPolicyKubernetes CronJob 行为
Allow允许同一 CronJob 的多个 Job 并发。
Forbid前一 Job 未完成时,跳过新一次执行。
Replace用新 Job 替换仍在运行的旧 Job。

这些策略仅作用于同一个 CronJob 创建的 Job。其他 CronJob 或手工任务仍需业务级协调。Replace 的取消也无法撤销已经提交的外部结果。

5. 分片​

按租户、日期、主键区间或稳定哈希拆分任务。每个 shard 保存独立状态,执行器并行领取。失败后只恢复未完成部分。

分片需要覆盖全部输入,并避免重复归属。记录数相同也会因单条成本不同产生倾斜。应按耗时调整粒度,热点分片还可继续拆分。

一次实例要固定输入边界。对单调递增主键,可记录本轮上界 max_id。任务再用主键游标推进。并发新增数据进入下一轮,避免扫描范围无限增长。要求一致快照时,还需数据库快照或版本边界。

6. 租约与所有者​

领取分片时,用共享存储原子设置 owner 和租约截止时间。时间判断应使用一致的存储端时钟。续租通过 owner 与版本条件更新。

租约过期后,新执行器可以接管。旧执行器在暂停后恢复,仍有机会发出写入。因此仅在客户端检查租约会留下竞争窗口。

每次接管分配递增 token,并让资源端记录新版本。后续写入携带 token,资源端原子校验其有效性。旧 token 的请求应被拒绝,详见下例。

6.1 过期执行器隔离​

假设 A 持有 token=7,暂停后租约过期。B 接管并安装 token=8。A 恢复时仍携带 7,资源端因版本落后拒绝写入。

若结果与租约都在同一数据库,可在事务中锁定任务行。事务检查 owner、token 与有效期,再写业务结果和检查点。检查和写入共同受该事务保护。

外部存储需自己原子验证 token。若它只比较已见最大版本,新 token 必须先到达该存储。仅给请求加字段而让下游忽略,无法隔离旧写入。外部 API 不支持该协议时,还需幂等和结果核对。

7. 检查点​

检查点记录最后可靠完成的主键或游标。业务结果与检查点在同一事务提交,可避免中间失败。跨系统副作用则需要稳定请求 ID 和结果查询。

并行批次应按连续完成范围推进。后面的批次完成时,前面的缺口仍需保留。提前跳过缺口会在恢复时漏处理。

offset 分页易受数据增删影响。按稳定键继续扫描,更便于重建和恢复。

8. 重试与补跑​

重试延续同一实例,增加尝试次数。补跑则创建或恢复错过计划对应的实例。账单任务可逐期补齐,快照任务可只保留最新一期。

Kubernetes 的 startingDeadlineSeconds 控制允许迟到多久。超过该窗口的计划会被跳过。Job 的 activeDeadlineSeconds 则限制运行时长。运行超限会终止相关 Pod,并让 Job 失败。

Job 的 backoffLimit 限制失败重试次数。达到运行时限会优先终止,剩余重试次数也随之失去意义。失败后需通过业务实例状态决定是否重新创建任务。

8.1 时区与计划标识​

Kubernetes CronJob 可以用 .spec.timeZone 指定时区,例如 Etc/UTC。计划时间应转成明确的 UTC 时间点或携带偏移。

夏令时会产生重复或缺失的本地时间。业务需定义按自然日还是绝对时间结算。实例 ID 使用计划时间,而非重试开始时间。

9. 监控​

比较预期实例与实际实例,发现漏调。再记录调度延迟、排队时间和执行耗时。

每个分片记录进度、接管次数和最老未完成时间。重试、幂等命中和最终业务数量都应可核对。只看最近一次成功会遗漏中间失败的计划。

10. 常见问题​

10.1 分布式锁与一次有效结果​

锁协调并发领取,持久化业务约束负责结果幂等。崩溃后重试要读取原实例,再恢复未完成工作。

10.2 Cron 表达式的时区​

11 · 面试题卡片​

11.1 如何设计可分片、可重试且不会重复产生业务结果的定时任务​

出现公司:字节跳动、Zoom

题型:综合题

考察重点

  • 调度触发与业务执行的边界。
  • 稳定实例 ID、租约、分片与检查点。
  • 重复、漏调、补跑和幂等副作用。

相关内容:调度时间与执行时间至监控。

参考回答

用稳定实例 ID 去重触发,用租约分配分片,再用业务幂等和 fencing token 控制重试与接管。

共享数据库通过唯一键保存实例状态,大任务拆为稳定分片,由执行器原子领取。

检查点只记录已完成范围,并与业务结果原子提交,或使用持久化幂等机制。接管后由资源端拒绝旧 token 的写入。补跑按计划实例进行,并限速核对业务结果。

11.2 租约过期后旧执行器恢复,怎样避免它覆盖新结果?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:暂停恢复、递增版本和资源端验证。

相关内容:租约与所有者、过期执行器隔离。

参考回答

接管时分配并安装更新的 fencing token。

每次写入由资源端原子验证 token,拒绝旧执行器。检查点与业务同库时,可把校验和更新放入同一事务。外部 API 还需自身支持 token,或提供幂等恢复协议。

11.3 startingDeadlineSeconds 和 activeDeadlineSeconds 分别限制什么?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:计划迟到与 Job 运行时长。

相关内容:重试与补跑。

参考回答

startingDeadlineSeconds 限制 CronJob 的迟到启动窗口。

activeDeadlineSeconds 限制 Job 的运行时长。前者超限跳过该计划,后者超限终止运行并标记失败。backoffLimit 另外限制 Job 的失败重试次数。

12. 参考资料​