Java面试要点:定时任务、防重、分布式调度与补偿
前言
任务调度是企业系统里很常见的后台能力:
- 订单超时关闭。
- 对账。
- 数据同步。
- 报表生成。
- 业务补偿。
- 定时通知。
面试会问:
- 定时任务怎么做防重。
- 多实例部署怎么避免重复执行。
- 任务失败怎么办。
- 为什么不能只靠
@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: 重试
分布式调度怎么避免重复执行
企业里最常见的问题是:同一个任务在多台机器上被重复执行。
常见解决方式:
- 任务加锁抢占。
- 数据库选主。
- 分片调度。
- 任务实例标识幂等。
方案一:全局抢锁
简单,但竞争大。
方案二:分片调度
把任务按业务 key 或数据范围切分给不同执行器。
优点:
- 提升吞吐。
- 降低单机压力。
适合:
- 大量独立任务。
方案三:主从选举
只有主节点执行调度。
适合:
- 中心化任务。
对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 抢锁 | 简单 | 争用大 |
| 分片 | 吞吐高 | 切分复杂 |
| 主从选举 | 逻辑清晰 | 单主压力大 |
失败重试和补偿
任务失败后的处理非常重要。
常见方式:
- 立即重试。
- 延迟重试。
- 人工补偿。
- 数据修复任务。
例如对账任务失败后:
- 记录失败批次。
- 自动重试。
- 超过阈值告警。
- 进入人工介入。
面试重点:
真正可靠的调度系统不是“任务一定成功”,而是“失败后可重试、可追踪、可补偿”。
调度任务的工程要求
企业调度任务通常要满足:
- 幂等。
- 可重复执行。
- 可观测。
- 有超时控制。
- 有告警。
- 有审计日志。
常见问题:
- 任务执行超过周期。
- 下游接口不稳定。
- 任务堆积。
- 人工误触发。
高频面试题
为什么 @Scheduled 不适合复杂业务?
因为它太轻,缺少任务管理、集群控制、日志和补偿能力。
定时任务为什么要防重?
因为多实例部署、网络抖动、重试、手工触发都可能导致同一任务重复执行。
调度任务为什么要有状态表?
因为任务只有执行日志还不够,还要知道当前状态、重试次数、失败原因和补偿进度。
什么时候用分布式调度?
当任务很多、执行器很多、需要统一管理和观察时。
任务执行超时怎么办?
要有超时中断、监控告警、任务拆分和补偿机制。
总结
任务调度的回答主线:
- 小任务用
@Scheduled,复杂任务用 Quartz 或平台。 - 多实例一定要防重。
- 失败要可重试、可补偿、可追踪。
- 大任务要分片和限时。
- 调度系统要具备监控、日志和告警。
企业里的任务调度不是“到点跑个方法”,而是一个完整的后台作业系统。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Junly博客!
评论


