前言

任务调度是企业系统里很常见的后台能力:

  • 订单超时关闭。
  • 对账。
  • 数据同步。
  • 报表生成。
  • 业务补偿。
  • 定时通知。

面试会问:

  • 定时任务怎么做防重。
  • 多实例部署怎么避免重复执行。
  • 任务失败怎么办。
  • 为什么不能只靠 @Scheduled
  • 分布式调度和本地调度怎么选。

定时任务的基本形态

flowchart TD
    A[定时触发] --> B[任务调度器]
    B --> C[执行任务]
    C --> D{是否成功}
    D -->|是| E[记录成功]
    D -->|否| F[重试/补偿/告警]

常见任务:

  • 每天凌晨生成日报。
  • 每 5 分钟同步库存。
  • 每 30 分钟扫描超时订单。
  • 每小时做一次对账。

方案一:Spring @Scheduled

优点:

  • 简单。
  • 成本低。

缺点:

  • 单机简单,多实例容易重复执行。
  • 任务失败后补偿能力弱。
  • 不适合复杂调度中心。

适合:

  • 单体应用。
  • 小范围任务。

方案二:Quartz

优点:

  • 支持更丰富的调度表达。
  • 有任务持久化、集群模式。

缺点:

  • 配置和维护成本高。
  • 对业务开发来说偏重。

适合:

  • 传统后台系统。
  • 对触发表达要求较高的任务。

方案三:分布式调度平台

常见能力:

  • 任务管理。
  • 在线编辑。
  • 执行器集群。
  • 日志查看。
  • 告警。
  • 失败重试。

优点:

  • 运维友好。
  • 适合大规模任务。

缺点:

  • 依赖平台。
  • 学习成本高。

适合:

  • 企业级平台。
  • 多业务线共享调度能力。

防重怎么做

任务防重是调度场景最重要的问题之一。

方案一:数据库唯一约束

适合任务结果有业务主键的场景。

优点:

  • 简单可靠。

缺点:

  • 只能防重复写入。

方案二:Redis 分布式锁

适合多实例抢占执行权。

优点:

  • 实现直观。

缺点:

  • 需要处理 TTL、续期和误删问题。

方案三:任务状态表

记录任务是否已执行、执行中、失败、成功。

优点:

  • 可追踪。
  • 方便补偿。

缺点:

  • 实现更完整。
stateDiagram-v2
    [*] --> WAIT
    WAIT --> RUNNING: 抢占成功
    RUNNING --> SUCCESS: 执行完成
    RUNNING --> FAILED: 执行失败
    FAILED --> WAIT: 重试

分布式调度怎么避免重复执行

企业里最常见的问题是:同一个任务在多台机器上被重复执行。

常见解决方式:

  1. 任务加锁抢占。
  2. 数据库选主。
  3. 分片调度。
  4. 任务实例标识幂等。

方案一:全局抢锁

简单,但竞争大。

方案二:分片调度

把任务按业务 key 或数据范围切分给不同执行器。

优点:

  • 提升吞吐。
  • 降低单机压力。

适合:

  • 大量独立任务。

方案三:主从选举

只有主节点执行调度。

适合:

  • 中心化任务。

对比:

方案 优点 缺点
抢锁 简单 争用大
分片 吞吐高 切分复杂
主从选举 逻辑清晰 单主压力大

失败重试和补偿

任务失败后的处理非常重要。

常见方式:

  • 立即重试。
  • 延迟重试。
  • 人工补偿。
  • 数据修复任务。

例如对账任务失败后:

  1. 记录失败批次。
  2. 自动重试。
  3. 超过阈值告警。
  4. 进入人工介入。

面试重点:

真正可靠的调度系统不是“任务一定成功”,而是“失败后可重试、可追踪、可补偿”。

调度任务的工程要求

企业调度任务通常要满足:

  • 幂等。
  • 可重复执行。
  • 可观测。
  • 有超时控制。
  • 有告警。
  • 有审计日志。

常见问题:

  • 任务执行超过周期。
  • 下游接口不稳定。
  • 任务堆积。
  • 人工误触发。

高频面试题

为什么 @Scheduled 不适合复杂业务?

因为它太轻,缺少任务管理、集群控制、日志和补偿能力。

定时任务为什么要防重?

因为多实例部署、网络抖动、重试、手工触发都可能导致同一任务重复执行。

调度任务为什么要有状态表?

因为任务只有执行日志还不够,还要知道当前状态、重试次数、失败原因和补偿进度。

什么时候用分布式调度?

当任务很多、执行器很多、需要统一管理和观察时。

任务执行超时怎么办?

要有超时中断、监控告警、任务拆分和补偿机制。

总结

任务调度的回答主线:

  1. 小任务用 @Scheduled,复杂任务用 Quartz 或平台。
  2. 多实例一定要防重。
  3. 失败要可重试、可补偿、可追踪。
  4. 大任务要分片和限时。
  5. 调度系统要具备监控、日志和告警。

企业里的任务调度不是“到点跑个方法”,而是一个完整的后台作业系统。