分布式调度模型:Master-Worker、Leader-Follower、共享状态与无状态调度
说到分布式调度,很多人第一反应就是「选主」。但说实话,选主只是万里长征第一步。真正让我头疼的,是选完主之后,任务到底怎么分配、状态怎么同步、挂了怎么恢复。
我这些年接触过的调度系统,基本逃不出四种模型:Master-Worker、Leader-Follower、共享状态调度、无状态调度。每种模型都有自己的脾气,选错了,后面全是坑。
Master-Worker架构:最经典,也最容易被误解
Master-Worker,说白了就是一个老板带一群小弟。Master负责拆任务、派任务、收结果;Worker只管埋头干活。
核心逻辑:Master是唯一的大脑,Worker是无状态的执行者。
我个人的习惯:在中小规模集群(几十台节点)里,Master-Worker是最稳的选择。但要注意,Master不能成为瓶颈。
我曾经在一个数据清洗项目里用过这种模型。Master节点负责从消息队列里拉取任务,然后分发给20个Worker。每个Worker处理完就写结果到共享存储。看起来挺完美,对吧?
结果上线第一天就出问题了——Master挂了。所有Worker瞬间变成无头苍蝇,任务全部卡住。
避坑指南:Master-Worker最大的弱点就是单点故障。我曾经吃过这个亏,后来加了备用Master,用ZooKeeper做选主,才算踏实。
适用场景:
- 任务可以拆分成独立子任务
- Worker之间不需要通信
- 集群规模在100节点以内
代码示例(伪代码):
// Master节点
while (true) {
task = queue.poll()
worker = selectIdleWorker()
worker.assign(task)
}
// Worker节点
while (true) {
task = master.fetchTask()
result = execute(task)
master.reportResult(result)
}
Leader-Follower模式:去中心化的优雅方案
Leader-Follower和Master-Worker最大的区别是什么?Leader也是Worker之一。它不光是发号施令的,自己也干活。
你想想看,这种设计天然解决了「Master闲着、Worker累死」的问题。而且Leader挂了,随便拉一个Follower顶上就行,切换成本极低。
核心机制:
- 所有节点平等,谁抢到领导权谁就是Leader
- Leader负责协调,但也参与执行
- Leader挂了,自动选举新Leader
我的经验:在Raft协议里,Leader-Follower模式用得最多。我做过一个日志复制系统,Leader负责接收写请求,然后同步给Follower。Leader自己也要处理读请求,不会闲着。
但这里有个坑——Leader如果既要协调又要干活,压力会很大。我记得有一次压测,Leader节点CPU冲到90%,Follower才30%。后来我调整了策略,让Leader只做轻量级任务,重活丢给Follower。
适用场景:
- 需要高可用、自动故障转移
- 节点数量适中(10-50个)
- 任务执行时间差异不大
共享状态调度:一致性是最大的敌人
共享状态调度,说白了就是所有节点都看同一份数据。谁抢到锁,谁就执行任务。
这种模型的好处是简单——状态都在数据库里,谁都能读。但坏处也很明显:并发冲突、锁竞争、性能瓶颈。
实现方式:
- 基于数据库的行锁或乐观锁
- 基于分布式锁(Redis、ZooKeeper)
- 基于事务日志
我曾经踩过的坑:用MySQL做共享状态调度,任务表里有个status字段。多个Worker同时抢任务,用UPDATE ... WHERE status=0 LIMIT 1。结果并发一高,死锁频发。后来改成Redis的SETNX,才解决问题。
性能对比:
| 方案 | 一致性 | 性能 | 复杂度 |
|---|---|---|---|
| 数据库行锁 | 强 | 低 | 低 |
| Redis分布式锁 | 最终 | 中 | 中 |
| ZooKeeper | 强 | 高 | 高 |
嗯,这里要注意:共享状态调度不适合高频任务。如果每秒几千个任务,数据库根本扛不住。我建议每秒1000以内的任务量,用Redis锁就够了。
无状态调度:弹性伸缩的终极答案
无状态调度,说白了就是所有节点都不保存状态。任务来了,谁有空谁干,干完就忘。
你想想看,这种模型有多爽——随便加节点、随便减节点,不用考虑数据迁移。Kubernetes的调度器就是典型例子。
核心设计:
- 任务信息放在外部存储(消息队列、数据库)
- 调度器只负责分配,不保存任何中间状态
- 节点挂了,任务重新入队,其他节点接着干
我个人的建议:如果你的业务允许任务重复执行(幂等),无状态调度是最省心的。我做过一个日志处理系统,每天几亿条日志,用Kafka + 无状态Worker,扩容缩容跟玩一样。
但无状态调度也有代价——任务必须幂等。如果任务不能重复执行,你就得额外加去重逻辑,反而更复杂。
适用场景:
- 任务可以重复执行
- 需要弹性伸缩
- 集群规模大(1000+节点)
四种模型对比
| 模型 | 状态管理 | 容错性 | 扩展性 | 典型场景 |
|---|---|---|---|---|
| Master-Worker | Master集中管理 | 低(单点故障) | 中 | 批处理、ETL |
| Leader-Follower | Leader协调 | 高 | 中 | 分布式数据库、共识系统 |
| 共享状态 | 外部存储 | 中 | 低 | 任务队列、定时调度 |
| 无状态 | 无 | 高 | 高 | 微服务、流处理 |
核心逻辑关系图
这张图把四种模型的关系理清楚了。你看,从Master-Worker到无状态调度,其实是一条「去中心化」的演进路线。越往右,弹性越好,但实现复杂度也越高。
我的建议:别一上来就追求最复杂的方案。我见过太多团队,明明只有10台机器,非要上无状态调度,结果被幂等和去重搞得焦头烂额。先想清楚你的场景,再选模型。
最后说一句:没有银弹。每种模型都有它的甜蜜点,也有它的痛点。理解了这些,你才能在面对具体问题时,做出不后悔的选择。