网络技术26-分布式一致性协议——多节点协作的“共识机制“
⏱️ 阅读时长:约15分钟 | 🔥 难度:进阶
标签:分布式系统一致性协议RaftPaxosZooKeeper
开场白
想象一下,你和五个朋友决定周末聚餐。有人想吃火锅,有人想吃烧烤,还有人坚持日料。如果每个人都按自己的想法行动,结果要么是六个人去了六个地方,要么是在餐厅门口吵到打起来。分布式系统里的多个节点,就像这群各怀心思的朋友——一致性协议,就是让他们达成共识、不打架的规则。
在分布式系统的世界里,数据分散在成百上千台机器上。如何让这些机器对"某条数据是什么"达成一致?这就是分布式一致性协议要解决的核心问题。今天,我们就用最接地气的方式,把 CAP 定理、2PC、Paxos、Raft 这些听起来高大上的概念,掰开了揉碎了讲清楚。
一、CAP 定理与 BASE 理论:分布式世界的"不可能三角"
1.1 CAP 定理:鱼与熊掌不可兼得
2000年,UC Berkeley 的 Eric Brewer 教授提出了著名的 CAP 定理。它告诉我们:分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)这三项中的两项。
💡生活化理解
想象你开了一家连锁奶茶店,有三家分店。CAP 就像是:
- C(一致性):所有店的菜单和价格必须完全一样
- A(可用性):每家店必须随时能接单,不能关门
- P(分区容错性):即使某两家店之间的电话线断了,它们也要能独立运营
问题来了:如果两家店之间的通信断了(P 发生),你要么让其中一家暂停营业保证数据一致(牺牲 A),要么允许两家店暂时数据不一致但都能营业(牺牲 C)。三者不可兼得,这就是分布式系统的宿命。
┌─────────────────────────────────────────────────────────┐ │ CAP 定理示意图 │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ │ │ / 一致性(C) \ │ │ / Consistency \ │ │ / \ │ │ / ╔═══════════╗ \ │ │ / ║ 不可能 ║ \ │ │ / ║ 三角 ║ \ │ │ / ╚═══════════╝ \ │ │ / \ │ │ / 可用性(A) 分区容错(P) \ │ │ / Availability Partition \ │ │ / \ │ │ └────────────────────────────────────┘ │ │ │ │ 常见组合: │ │ • CP 系统:ZooKeeper、etcd、HBase │ │ • AP 系统:Cassandra、DynamoDB、Eureka │ │ • CA 系统:传统单机数据库(非分布式) │ └─────────────────────────────────────────────────────────┘1.2 BASE 理论:退一步海阔天空
既然 CAP 告诉我们强一致性很难,那能不能退而求其次?BASE 理论应运而生:
- Basically Available(基本可用):系统出现故障时,允许损失部分可用性,但核心功能必须可用
- Soft state(软状态):允许系统中的数据存在中间状态,不影响整体可用性
- Eventually consistent(最终一致性):不保证实时一致,但保证最终所有节点数据一致
核心思想:BASE 是对 CAP 中 AP 方案的延伸,强调"高可用优先,一致性可以稍后再补"。就像网购时,你先看到"库存充足"下单了,实际上系统后台可能正在同步库存数据——这就是软状态和最终一致性的体现。
二、2PC 与 3PC:分布式事务的"举手表决"
2.1 两阶段提交(2PC):先举手,再行动
2PC(Two-Phase Commit)是最经典的分布式事务协议。它把事务提交分成两个阶段:
┌────────────────────────────────────────────────────────────┐ │ 2PC 两阶段提交流程 │ ├────────────────────────────────────────────────────────────┤ │ │ │ 协调者(Coordinator) 参与者(Participants) │ │ │ │ │ │ Phase 1 │ 1. Can you commit? ─────▶│ │ │ (投票) │ │ │ │ │◀──────── 2. Yes/No ─────────│ │ │ │ (所有参与者回复) │ │ │ │ │ │ │ │ 如果全部 Yes: │ │ │ Phase 2 │ │ │ │ (执行) │ 3. Commit ──────────────▶│ │ │ │ │ │ │ │◀──────── 4. ACK ────────────│ │ │ │ │ │ │ │ 如果有 No: │ │ │ │ 3. Rollback ────────────▶│ │ │ │ │ │ └────────────────────────────────────────────────────────────┘第一阶段(投票阶段):协调者询问所有参与者"你能执行这个操作吗?",参与者执行本地事务但不提交,然后回复 Yes 或 No。
第二阶段(执行阶段):如果所有参与者都回复 Yes,协调者发送 Commit 指令;如果有任何参与者回复 No,协调者发送 Rollback 指令。
💡聚餐决策版
你们六个人决定去哪吃饭:
- 第一阶段:群主(协调者)问每个人"你能接受吃火锅吗?“,每个人心里盘算一下,能接受的举手说"行”,不能接受的举手说"不行"。
- 第二阶段:如果所有人都说"行",群主宣布"那就这么定了,大家都去火锅店";如果有人说了"不行",群主宣布"这个方案作废,我们再想别的"。
2PC 的致命缺陷:
- 同步阻塞:参与者需要锁定资源等待协调者指令,性能差
- 单点故障:协调者挂了,整个事务就卡住了
- 数据不一致风险:如果协调者在第二阶段挂了,部分参与者可能提交了,部分没提交
2.2 三阶段提交(3PC):再加一道保险
3PC 在 2PC 的基础上增加了一个阶段,试图解决 2PC 的阻塞问题:
- CanCommit 阶段:协调者询问参与者"你理论上能不能执行?"(不锁定资源)
- PreCommit 阶段:协调者通知参与者"准备执行"(预锁定资源)
- DoCommit 阶段:真正提交或回滚
3PC 的改进:引入了超时机制。如果参与者超时没收到协调者的指令,可以根据当前状态自己决定是提交还是回滚。这就像聚餐时群主失联了,大家约定:如果已经说"准备去了"就默认去,如果只是"理论上能去"就默认不去。
但说实话,3PC 并没有完全解决 2PC 的问题,只是降低了阻塞概率。在网络分区的情况下,仍然可能出现数据不一致。所以实际生产中,2PC/3PC 主要用于数据库内部的分布式事务(如 MySQL XA),很少直接用于微服务架构。
三、Paxos 算法:议会投票的"民主典范"
3.1 Paxos 是什么?
Paxos 算法由 Leslie Lamport 于 1990 年提出(论文直到 1998 年才发表,因为审稿人觉得"太无聊")。它是分布式一致性算法的鼻祖,Raft、ZAB 等都是它的变种或简化版。
💡Paxos 的核心比喻
Paxos 就像古希腊城邦的议会投票:
- 有一个提议者(Proposer):相当于议员,负责提出议案
- 有一群接受者(Acceptor):相当于议会成员,负责投票
- 有若干学习者(Learner):相当于吃瓜群众,只负责知道最终结果
议会要通过一个决议,必须获得**多数派(超过半数)**的同意。而且一旦决议通过,就不可更改。
3.2 Paxos 的两个阶段
Paxos 算法分为两个阶段,每个阶段都是多数派投票:
┌─────────────────────────────────────────────────────────────┐ │ Paxos 算法流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Phase 1: Prepare(准备阶段) │ │ ═══════════════════════════ │ │ │ │ Proposer Acceptors │ │ │ 1. Prepare(n) ─────┬─────▶ │ │ │ │ │ │ │ │◀──────────┴──── Promise ──┘ │ │ │ (承诺不接受编号<n的提案) │ │ │ │ │ Phase 2: Accept(接受阶段) │ │ ══════════════════════════ │ │ │ │ │ 2. Accept(n,v) ─────┬─────▶ │ │ │ │ │ │ │ │◀──────────┴──── Accepted ─┘ │ │ │ (多数派接受后,v被选定) │ │ │ │ 关键约束: │ │ • 每个 Acceptor 必须接受它收到的第一个提案 │ │ • 如果已经接受过提案,Promise 时要告知 Proposer │ │ • Proposer 收到多数 Promise 后才能进入 Phase 2 │ └─────────────────────────────────────────────────────────────┘Phase 1 - Prepare 阶段:
- Proposer 选择一个提案编号 n,向超过半数的 Acceptor 发送 Prepare(n) 请求
- Acceptor 收到 Prepare(n) 后,如果 n 大于它之前承诺过的所有编号,就承诺不再接受编号小于 n 的提案,并返回它已经接受过的最大编号的提案(如果有)
Phase 2 - Accept 阶段:
- 如果 Proposer 收到了多数 Acceptor 的 Promise 回复,它就选择一个值 v(如果 Acceptor 返回了已接受的值,就用那个值;否则用自己的值),发送 Accept(n, v) 请求
- Acceptor 收到 Accept(n, v) 后,如果不违反之前的承诺,就接受这个提案
- 一旦某个值被多数 Acceptor 接受,它就被选定了
3.3 为什么 Paxos 这么难理解?
Paxos 被称为"唯一正确的一致性算法",但也被称为"最难理解的算法"。难点在于:
- 活锁问题:多个 Proposer 同时提案,可能导致互相抢占,谁也成功不了
- 实现复杂:Multi-Paxos(连续多个值的共识)需要额外的 Leader 选举机制
- 边界情况多:网络分区、节点宕机、消息丢失等各种异常情况都要处理
著名的 Paxos 笑话:Lamport 后来写了一篇《Paxos Made Simple》(Paxos made simple),但据说能看懂的人依然寥寥无几。有人说:“世界上有两种分布式一致性协议,一种是 Paxos,另一种是 Paxos 的简化版。”
四、Raft 算法:选班长的"民主简化版"
4.1 为什么需要 Raft?
2013年,斯坦福大学的 Diego Ongaro 和 John Ousterhout 发表了 Raft 论文。他们的目标是:设计一个和 Paxos 一样正确,但更容易理解的共识算法。
Raft 做到了。它把复杂的共识问题拆解成三个相对独立的子问题:
- 领导者选举(Leader Election):谁当老大
- 日志复制(Log Replication):老大怎么把命令同步给所有人
- 安全性(Safety):保证各种异常情况下的正确性
💡Raft 的核心比喻
Raft 就像班级选班长:
- 领导者(Leader):班长,所有决策由班长下达
- 跟随者(Follower):普通同学,听从班长指挥
- 候选人(Candidate):想当班长的人,需要拉票
班级里只能有一个班长。班长负责传达老师的指令,同学们记录在本子上。如果班长请假了,大家就重新选举。
4.2 领导者选举:谁当老大?
Raft 使用任期(Term)的概念,每个任期最多只有一个 Leader:
┌─────────────────────────────────────────────────────────────┐ │ Raft 领导者选举流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Follower Candidate Leader │ │ (跟随者) (候选人) (领导者) │ │ │ │ │ │ │ │ 超时没收到心跳 │ │ │ │ │──────────────▶ │ │ │ │ │ 增加任期号 │ │ │ │ │ 给自己投票 │ │ │ │ │ │ │ │ │ │◀───────── RequestVote ──────────│ │ │ │ │ (向所有节点拉票) │ │ │ │ │ │ │ │ │──────── Vote ─▶│ │ │ │ │ (同意投票) │ │ │ │ │ │ │ │ │ │ │ 获得多数票 │ │ │ │ │──────────────▶│ │ │ │ │ 成为 Leader │ │ │ │ │ 发送心跳包 │ │ │ │◀──────────── Heartbeat ────────│ │ │ │ │ │ │ │ 选举规则: │ │ • 每个任期,每个节点最多投一票 │ │ • 先到先得(Candidate 先请求就投给谁) │ │ • 任期号大的优先(过时的 Leader 自动下台) │ └─────────────────────────────────────────────────────────────┘选举过程:
- 每个 Follower 有一个随机的选举超时时间(150-300ms)
- 如果超时还没收到 Leader 的心跳,就变成 Candidate,增加任期号,给自己投票
- Candidate 向所有其他节点发送 RequestVote 请求
- 如果收到超过半数的投票,就成为 Leader
- 新 Leader 立即发送心跳包,阻止新的选举
4.3 日志复制:班长怎么传达指令?
Leader 负责接收客户端的请求,然后把操作日志复制给所有 Follower:
// Leader 收到客户端写请求 function clientRequest(command) { // 1. 先把命令追加到自己的日志 log.append({term: currentTerm, command: command}) // 2. 向所有 Follower 发送 AppendEntries RPC for each follower in followers: send AppendEntries { term: currentTerm, leaderId: self, prevLogIndex: nextIndex[follower] - 1, prevLogTerm: log[prevLogIndex].term, entries: log[nextIndex[follower]:], leaderCommit: commitIndex } // 3. 如果收到多数成功回复,就提交 if majoritySuccess(): commitIndex++ applyToStateMachine() replyToClient(success) } // Follower 处理 AppendEntries function handleAppendEntries(args) { if args.term < currentTerm: return reject // 拒绝过期的 Leader // 检查 prevLog 是否匹配 if log[args.prevLogIndex].term != args.prevLogTerm: return reject // 日志不一致,需要 Leader 回退 // 追加新日志条目 log.append(args.entries) // 更新 commitIndex if args.leaderCommit > commitIndex: commitIndex = min(args.leaderCommit, log.lastIndex()) return success }关键机制:
- 日志匹配特性:如果两个日志在相同索引位置的任期号相同,那么它们之前的所有条目都相同
- 提交规则:Leader 只能提交自己任期内的日志条目(旧任期的日志需要等新日志一起提交)
- 一致性检查:AppendEntries 携带 prevLogIndex 和 prevLogTerm,Follower 检查是否匹配
4.4 安全性保证
Raft 通过以下机制保证安全:
- 选举限制:Candidate 必须包含所有已提交的日志才能当选(RequestVote 时比较日志的最后任期和索引)
- 提交规则:不能直接提交旧任期的日志,必须等到当前任期有日志提交时一起提交
- 状态机安全:一旦某个日志条目被提交,所有节点最终都会应用相同的命令
💡Raft 的优势:相比 Paxos,Raft 的 Leader 机制让算法更容易理解——所有写操作都经过 Leader,避免了 Paxos 中多 Proposer 冲突的活锁问题。etcd、Consul、Nacos 等知名项目都使用 Raft 作为共识算法。
五、ZAB 协议:ZooKeeper 的"原子广播"
5.1 ZAB 是什么?
ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 使用的原子广播协议。它专门为 ZooKeeper 设计,目标是保证:
- 顺序一致性:客户端的更新按发送顺序应用
- 原子性:更新要么成功要么失败,没有中间状态
- 单一系统映像:客户端无论连到哪个服务器,看到的数据都一样
- 可靠性:一旦更新被应用,它会被持久化
- 实时性:客户端在一定时间内能读到最新数据
5.2 ZAB 的两个阶段
ZAB 协议把运行时分两个阶段:
┌─────────────────────────────────────────────────────────────┐ │ ZAB 协议运行阶段 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ 崩溃恢复 │─────────────▶│ 消息广播 │ │ │ │ (Recovery) │ Leader 选举 │ (Broadcast) │ │ │ └──────────────┘ 完成 └──────────────┘ │ │ ▲ │ │ │ │ │ Leader 崩溃 │ │ └────────────────────────────┘ │ │ │ │ 崩溃恢复阶段: │ │ • 选举新的 Leader(拥有最大 zxid 的节点优先) │ │ • Leader 同步数据给 Follower │ │ • 确保过半节点数据一致后才对外服务 │ │ │ │ 消息广播阶段: │ │ • 类似两阶段提交 │ │ • Leader 生成全局唯一的 zxid │ │ • 过半节点 ACK 后才提交 │ └─────────────────────────────────────────────────────────────┘崩溃恢复阶段:
- Leader 选举:选择拥有最大 ZXID(事务ID)的节点作为 Leader
- 数据同步:Leader 确保 Follower 和自己数据一致
- 加入集群:同步完成后,Follower 正式加入集群
消息广播阶段:
- Leader 收到写请求,生成全局唯一的 ZXID
- Leader 发送 Proposal 给所有 Follower
- Follower 写入本地日志,发送 ACK
- Leader 收到过半 ACK,发送 Commit
- 所有节点提交事务
5.3 ZAB vs Raft
ZAB 和 Raft 很相似,但有一些关键区别:
| 特性 | ZAB | Raft |
|---|---|---|
| 设计目标 | 专门为 ZooKeeper 设计 | 通用共识算法 |
| 日志流向 | Leader → Follower(单向) | Leader → Follower(单向) |
| 事务 ID | ZXID(高32位是任期,低32位是计数) | (任期,索引)二元组 |
| Leader 选举 | 优先选数据最新的 | 随机超时,先到先得 |
| 读操作 | 可以从 Follower 读(可能读到旧数据) | 可以从 Follower 读(可能读到旧数据) |
六、Gossip 协议:最终一致性的"八卦传播"
6.1 什么是 Gossip 协议?
Gossip 协议(八卦协议)是一种基于流行病传播思想的分布式协议。节点之间像传播八卦一样随机交换信息,最终达到全网一致。
💡八卦传播版
想象你在一个聚会上听到了一个惊天大瓜:
- 你随机找两个人告诉他们
- 这两个人又各自随机找两个人
- 很快,整个聚会的人都知道了这个瓜
即使有人中途离场,或者有人没听清楚,最终大多数人还是会知道这个消息。这就是 Gossip 协议的精髓。
6.2 Gossip 的工作原理
┌─────────────────────────────────────────────────────────────┐ │ Gossip 协议传播过程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Round 1: Round 2: Round 3: │ │ │ │ A A A │ │ / \ /|\ /|\ │ │ B C B C D B C D E F │ │ / \ / \ /|\ /|\ │ │ D E E F G H I J K L │ │ │ │ 传播特点: │ │ • 每个周期随机选择 k 个邻居交换信息 │ │ • 信息像病毒一样指数级传播 │ │ • 容错性强,部分节点失效不影响整体 │ │ • 最终一致性,不保证实时一致 │ └─────────────────────────────────────────────────────────────┘Gossip 的两种模式:
- 反熵(Anti-Entropy):节点定期随机选择另一个节点,交换完整的副本数据,消除差异
- 谣言传播(Rumor Mongering):新信息像谣言一样传播,节点收到后标记为"热点",继续传播给其他节点,直到全网都知道
6.3 Gossip 的应用场景
Gossip 协议适合以下场景:
- 集群成员发现:Redis Cluster、Consul 用 Gossip 发现节点
- 配置传播:Cassandra 用 Gossip 传播节点状态
- 故障检测:通过心跳缺失发现节点故障
- 分布式数据库:DynamoDB、Cassandra 的数据同步
import random import time from threading import Thread class GossipNode: def __init__(self, node_id, peers): self.node_id = node_id self.peers = peers # 邻居节点列表 self.data = {} # 本地数据 self.version = {} # 数据版本号 def update(self, key, value): """更新本地数据""" self.data[key] = value self.version[key] = self.version.get(key, 0) + 1 print(f"[{self.node_id}] Updated {key}={value}, version={self.version[key]}") def gossip(self): """随机选择邻居交换数据""" if not self.peers: return # 随机选择 k 个邻居(这里 k=1) peer = random.choice(self.peers) # 交换数据(实际实现会用网络通信) print(f"[{self.node_id}] Gossiping with {peer.node_id}") self.merge_data(peer) peer.merge_data(self) def merge_data(self, other): """合并对方的数据(按版本号)""" for key, value in other.data.items(): other_ver = other.version.get(key, 0) my_ver = self.version.get(key, 0) if other_ver > my_ver: self.data[key] = value self.version[key] = other_ver print(f"[{self.node_id}] Merged {key}={value} from {other.node_id}") # 模拟三个节点 node_a = GossipNode("A", []) node_b = GossipNode("B", []) node_c = GossipNode("C", []) # 设置邻居关系 node_a.peers = [node_b, node_c] node_b.peers = [node_a, node_c] node_c.peers = [node_a, node_b] # A 更新数据 node_a.update("config", "v1") # 模拟多轮 gossip for i in range(5): print(f"\n=== Round {i+1} ===") node_a.gossip() node_b.gossip() node_c.gossip() time.sleep(0.1) print("\n=== Final State ===") for node in [node_a, node_b, node_c]: print(f"{node.node_id}: {node.data}")💡Gossip 的优缺点:
- 优点:去中心化、容错性强、可扩展性好、网络开销小
- 缺点:最终一致性(有延迟)、收敛时间不确定、消息可能重复传播
七、一致性协议选型指南:没有银弹
7.1 各种协议对比
| 协议 | 一致性级别 | 可用性 | 性能 | 复杂度 | 典型应用 |
|---|---|---|---|---|---|
| 2PC/3PC | 强一致 | 低(阻塞) | 低 | 中 | 数据库 XA 事务 |
| Paxos | 强一致 | 中 | 中 | 极高 | Chubby、PaxosStore |
| Raft | 强一致 | 中 | 中 | 中 | etcd、Consul、Nacos |
| ZAB | 强一致 | 中 | 中 | 中 | ZooKeeper |
| Gossip | 最终一致 | 高 | 高 | 低 | Cassandra、Consul |
7.2 选型决策树
┌─────────────────────────────────────────────────────────────┐ │ 一致性协议选型决策树 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 开始选型 │ │ │ │ │ ┌────────────┴────────────┐ │ │ ▼ ▼ │ │ 必须强一致? 可以接受最终一致? │ │ │ │ │ │ 是 ┌─┘ 是 ┌─┘ │ │ ▼ ▼ │ │ 需要事务? Gossip 协议 │ │ │ • Cassandra │ │ 是 ┌─┘ • Consul 服务发现 │ │ ▼ │ │ 2PC/3PC │ │ • 数据库分布式事务 │ │ │ │ 否 ┌─────────────────────────┐ │ │ ▼ ▼ │ │ 追求简单实现? 追求极致性能? │ │ │ │ │ │ 是 ┌┘ 是 ┌┘ │ │ ▼ ▼ │ │ Raft Paxos │ │ • etcd • 大规模系统 │ │ • Consul • 有专业团队维护 │ │ • Nacos │ │ │ │ 否 ┌─────────────────────────┐ │ │ ▼ │ │ ZAB / 定制协议 │ │ • ZooKeeper │ │ • 需要顺序保证的场景 │ └─────────────────────────────────────────────────────────────┘7.3 实战建议
🎯选型黄金法则
- 配置中心/服务发现:etcd(Raft)或 Consul(Raft + Gossip)
- 分布式锁/协调:ZooKeeper(ZAB)或 etcd
- 分布式事务:Seata(基于 2PC 优化)或 Saga 模式
- 高可用缓存:Redis Cluster(Gossip)或 Codis
- 海量数据存储:Cassandra(Gossip)或 TiDB(Raft)
记住三个不要:
- 不要为了追求强一致而牺牲所有性能
- 不要在需要事务的场景用最终一致性方案
- 不要自己实现 Paxos(除非你是 Google 或微信团队)
写在最后
分布式一致性协议,本质上是在一致性、可用性、分区容错性之间做权衡的艺术。没有最好的协议,只有最适合场景的协议。
从 CAP 定理的"不可能三角",到 2PC 的"举手表决",再到 Paxos 的"议会投票"、Raft 的"选班长"、Gossip 的"八卦传播"——每一种协议都是人类在分布式世界中的智慧结晶。
希望这篇文章能帮你建立起分布式一致性的整体认知。下次面试官问你"Raft 和 Paxos 有什么区别",或者架构师问你"这个场景选什么一致性方案",你能胸有成竹地回答。
📦 源码获取
本文所有代码示例已整理到 GitHub:
🔗GitHub 仓库:https://github.com/example/distributed-consensus-demos
包含内容:
- Raft 算法的 Python 简化实现
- Gossip 协议的完整模拟
- 2PC/3PC 的 Java 示例
- ZooKeeper 客户端操作示例
🤔 思考题
- 假设你设计一个电商库存系统,扣减库存时应该选强一致性还是最终一致性?为什么?
- Raft 的 Leader 选举中,如果两个 Candidate 同时获得相同数量的选票,会发生什么?怎么解决?
- 为什么 Paxos 允许有多个 Proposer,而 Raft 只允许一个 Leader?各有什么优缺点?
- 在跨地域的分布式系统中,CAP 定理如何指导你的架构设计?
- ZooKeeper 的 ZAB 协议为什么要设计崩溃恢复阶段?直接像 Raft 一样持续运行不行吗?
📚 系列文章预告
《网络协议系列》持续更新中:
- 下一篇:分布式事务的终极解决方案——从 2PC 到 Saga 再到 Seata
- 番外篇:etcd 源码解析:Raft 算法的工业级实现
- 实战篇:用 Go 语言手写一个 Raft 分布式 KV 存储
- 进阶篇:Paxos 的数学证明:为什么它能保证安全性?
👉关注专栏,不错过每一篇干货!
如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬
你的支持是我持续创作的动力!
标签:分布式系统一致性协议RaftPaxosZooKeeper
