Bully、Raft、ZAB 三大经典分布式选举算法
1. Bully 算法
1.1 算法思想 👑
Bully算法是一种基于节点ID的选举算法,核心思想是让最高ID的节点成为领导者。当节点发现协调者失效时,会向所有更高ID节点发起挑战,若没有响应则宣布自己为领导者。
1.2 算法原理 ⚙️
1.3 流程图 📊
1.4 C++实现关键代码
class BullyNode {
public:
BullyNode(int id, vector<int> peers) : node_id(id), peers(peers) {}
void startElection() {
bool higherNodeResponded = false;
for (int peer : peers) {
if (peer > node_id) {
// 向更高ID节点发送选举消息
if (sendElectionMessage(peer)) {
higherNodeResponded = true;
}
}
}
if (!higherNodeResponded) {
becomeLeader();
}
}
void becomeLeader() {
is_leader = true;
for (int peer : peers) {
sendLeaderAnnouncement(peer);
}
}
private:
int node_id;
vector<int> peers;
bool is_leader = false;
};
2. Raft 算法
2.1 算法思想 🚣
Raft通过任期(term)机制和日志复制实现分布式一致性,将问题分解为领导者选举、日志复制和安全性三个子问题。
2.2 状态转换图 🔄
2.3 选举流程 ⚡
2.4 C++实现关键代码
class RaftNode {
public:
enum State { FOLLOWER, CANDIDATE, LEADER };
void startElection() {
current_term++;
state = CANDIDATE;
votes_received = 1; // 投票给自己
// 请求其他节点投票
for (auto& peer : peers) {
RequestVoteRequest req;
req.term = current_term;
req.candidate_id = node_id;
req.last_log_index = log.last_index();
req.last_log_term = log.last_term();
sendRequestVote(peer, req);
}
// 设置选举超时
startElectionTimer();
}
void handleVoteResponse(const VoteResponse& res) {
if (res.term > current_term) {
stepDown(res.term);
return;
}
if (res.vote_granted) {
votes_received++;
if (votes_received > peers.size() / 2) {
becomeLeader();
}
}
}
void becomeLeader() {
state = LEADER;
// 初始化nextIndex和matchIndex
for (auto& peer : peers) {
next_index[peer] = log.last_index() + 1;
match_index[peer] = 0;
}
// 开始发送心跳
startHeartbeat();
}
};
3. ZAB 算法
3.1 算法思想 🐘
ZAB(ZooKeeper Atomic Broadcast)专为ZooKeeper设计,通过epoch机制和两阶段提交确保消息顺序和一致性。
3.2 算法架构 🏗️
3.3 恢复流程 ♻️
3.4 C++实现关键代码
class ZabNode {
public:
void runLeaderElection() {
current_epoch++;
election_state = LOOKING;
// 广播选举消息
ElectionMessage msg;
msg.epoch = current_epoch;
msg.zxid = last_zxid;
msg.sid = node_id;
broadcast(msg);
// 收集投票
map<int, ElectionMessage> votes;
while (votes.size() <= peers.size() / 2) {
ElectionMessage response = waitForResponse();
votes[response.sid] = response;
}
// 选择Leader(最高ZXID优先)
int leader_id = selectLeader(votes);
if (leader_id == node_id) {
becomeLeader();
} else {
becomeFollower(leader_id);
}
}
void broadcastTransaction(Transaction txn) {
// 阶段1:广播提案
Proposal prop;
prop.zxid = next_zxid++;
prop.txn = txn;
for (auto& peer : followers) {
sendProposal(peer, prop);
}
// 等待ACK
int ack_count = 0;
while (ack_count <= followers.size() / 2) {
if (receiveAck()) ack_count++;
}
// 阶段2:广播提交
CommitMessage commit;
commit.zxid = prop.zxid;
for (auto& peer : followers) {
sendCommit(peer, commit);
}
// 本地提交
applyTransaction(txn);
}
};
4. 算法对比分析
4.1 特性对比表 📋
| 特性 | Bully | Raft | ZAB |
|---|---|---|---|
| 选举基础 | 节点ID | 任期+日志 | Epoch+ZXID |
| 消息复杂度 | O(n²) | O(n) | O(n) |
| 领导者变更 | 立即生效 | 任期结束生效 | Epoch变更生效 |
| 数据一致性 | 不保证 | 强一致性 | 顺序一致性 |
| 适用场景 | 小规模集群 | 通用分布式系统 | 协调服务 |
4.2 适用场景分析 🔍

5. 实现注意事项
5.1 通用实现模式 🧩
5.2 关键挑战与解决方案 🛡️
| 挑战 | 解决方案 |
|---|---|
| 网络分区 | 超时机制+心跳检测 |
| 脑裂问题 | 多数派(Quorum)决策机制 |
| 拜占庭故障 | 数字签名+身份认证(非本文算法核心关注点) |
| 日志一致性 | 两阶段提交(2PC)+复制状态机 |
| 性能优化 | 批量提交+流水线复制 |
6. 参考
- 简单系统:选择Bully算法实现简单快速
- 数据强一致:Raft提供完整解决方案
- 协调服务:ZAB与ZooKeeper深度集成
- 大规模集群:考虑Raft变种或Paxos家族


3256

被折叠的 条评论
为什么被折叠?



