#raft
# Cluster membership changes
- 实现:增加两个 RPC
- AddServer RPC
- RemoveServer RPC
## AddServer RPC
- 
- **参数**
- newServer:添加新 server 的地址
- **返回值**
- status:添加成功返回 OK
- leaderHint:最新的 leader 地址(如果知道的话)
- **接收者实现**
1. 如果不是 leader 返回 NOT_LEADER
2. 在固定轮数内让新 server 赶上进度;
- 如果新 server 在一个选举超时内没有进度更新,或者最后一轮花费的时间超过选举超时,返回 TIMEOUT;
3. 等待 log 中之前的 configuration 变成 committed
4. 追加新的 configuration entry 到 log 中(日志内容:旧配置 + 新 server),使用新配置的 majority 来完成该条日志的 commit
5. 回复 OK
## RemoveServer RPC
- 
- **参数**
- oldServer:需要删除的 server 地址
- **返回值**
- status:如果删除成功返回 OK
- leaderHint:同上
- **接收者实现**
1. 回复 NOT_LEADER 如果当前接收者不是 leader
2. 等待 log 中之前的 configuration 变成 committed
3. 追加 new configuration entry 到 log 中(日志内容:旧的配置),使用新配置的 majority 完成该条日志的 commit
4. 回复 OK;并且如果删除的是当前 server ,执行退出
--------
# Safety
- 同一个 term 不能选出两个 leader
- 如果一次性添加 / 删除多个 servers 可能会出现(分裂成两个独立的 majorities)
- 
- 旧:3个节点;新:添加2个新节点(4 和 5)
- **single-server approach**
- 一次性只能添加 / 删除 一个 server
- 新旧配置的两个 majorities 总是会重叠,避免分裂成两个独立的 majorities
- 因此可以直接切换到 new configuration
- 当 leader 收到变更请求后,追加 new configuration ($C_{new}$) 到 log 中,并使用正常 raft 机制复制 它。
- 每个 server 上**新配置的生效时机**:当 $C_{new}$ 添加到它的 log 中时
- 即每个 server **不需要等待** $C_{new}$ entry 的 commit,**始终使用 log 中发现的最新配置即可**。
- 配置变更操作**完成的标志**:$C_{new}$ 变成 committed 后 ( 即复制到**新配置**下的 majority 中)
- 此时 leader 就可以确认: $C_{new}$ servers 的 majority 已经应用了 $C_{new}$;
- leader 也知道 没有应用 $C_{new}$ 的 servers 未来不会再组成 majority,而且它们也不会被选为 leader
- $C_{new}$ 的提交使三件事能够继续进行:
1. leader 可以确认配置变更已经成功完成
2. 如果配置变更是删除一个 server,那么这个 server 可以 shut down
3. 可以开始处理新的配置变请求
- 在此之前,overlapped configuration changes 可以会导致出现两个 majorities
- 问题:如果 leader 发生变更,新配置对应的 log 可能会被删除
- server 需要具备 **回滚** 到之前配置的能力
- 投票和日志复制需要的修改:
- server 需要接受 不在当前配置内的 leader 的 AppendEntries 请求,否则新加入的 server 就无法加入到集群
- server 需要处理 不在当前配置内的 candidate 的投票请求(如果日志足够新就同意)。
- 例如 3 个节点上添加一个新节点,如果挂掉一个,新节点的 vote 是必须的
------