任务调度

分布式调度挑战

在分布式环境下,多个调度器如何协调工作?

核心问题

分布式调度的核心问题:

1. 任务如何分配?
   ├─ 按任务 ID 分片
   ├─ 按队列分片
   └─ 按消费者分片

2. 如何避免重复执行?
   ├─ 分布式锁
   ├─ Lua 脚本原子操作
   └─ 数据库悲观锁

3. 如何处理故障?
   ├─ 心跳检测
   ├─ 主备切换
   └─ 任务迁移

调度策略

策略 1:分片调度

最直接的做法,是把任务按某个稳定维度切开。比如按任务 ID 取模,或者按业务队列划分。每个调度器只负责自己的分片,这样大家不会扫描同一批任务。

分片调度的好处是简单、可预测。调度器数量固定时,任务归属也很稳定。但它也有代价:如果某个分片任务特别多,其他分片很空,系统就会出现局部热点。

当前架构
分布式调度
多台调度器同时工作时,重点是分片、互斥、故障接管和重复执行控制。
调度集群
分片规则
领导者选举
心跳
互斥控制
任务锁
租约
幂等键
故障恢复
超时释放
任务迁移
补偿扫描

策略 2:动态分片

动态分片解决的是负载不均的问题。调度器定期上报心跳和处理能力,系统根据当前任务量重新分配分片。任务多的分片可以拆给更多调度器,任务少的分片可以合并。

这种方案更灵活,但需要额外维护“谁负责哪一段任务”的元数据。只要分配表出错,就可能出现无人调度或重复调度。因此动态分片一定要配合租约、版本号和心跳过期机制。

策略 3:主调度器 + 工作调度器

还有一种折中方案:由一个主调度器负责分配任务范围,多个工作调度器负责实际扫描和投递。主调度器不处理业务,只管理分工;工作调度器不争全局,只处理自己拿到的范围。

这个方案适合中等规模系统。它比静态分片更灵活,又比完全动态分片更容易理解。风险在于主调度器本身要高可用,所以必须支持主备切换。

读者要记住什么

分布式调度不是为了显得复杂,而是为了让系统在多台机器上仍然保持三件事:任务有人处理、任务不会被多人同时处理、某台机器挂了以后任务还能继续走。只要这三件事没有被证明,调度方案就还不完整。