定义
通过一个 Leader 来实现节点共识和日志一致
https://www.linkinstar.wiki/2019/06/12/golang/open-source-component/etcd-raft/
细节
通信
投票 RPC:候选人发起,选举期间,通知各个节点进行投票
日志 RPC:领导者发起,进行日志复制和提供心跳(没有日志的请求)
任期
任期单调递增
发现自己的任期小(收到任期大消息)会立即变成 follower
收到任期小的消息,直接拒绝
选举
Leader 定期心跳,保证自己的地位还在
Follower 指定时间没有收到心跳,进行自举
选票数高者当选
在一个任期内除非自己意外离线,否则一直为 Leader
每次投票只能投一个
日志更多者优先
日志
领导者不直接发送消息通知其他节点提交日志项,因为领导者的日志赋值 RPC 和心跳(没有日志的日志 PRC 请求)会包含当前最大的日志索引值。(这是一个优化,这样只要有半数以上的follower收到,那么本地提交就可以直接返回客户端结果了,不用再次所有再提交通知一次)
在 Raft 中日志必须是连续的
与 Multi-Paxos 相比
选举并不是一次 k-v 的共识,而是有了自己的方案,通过随机心跳和日志来完成
通过任期、心跳、随机时间、先来先服务、日志数量多个维度保证选举的 Leader 唯一性,减少选举失败的可能性和多次重复进行选举的可能性
新添加节点
很多人觉得新添加节点是一个很容易的事情,但是其实这是一个很困难的事情。
并不是你直接添加节点到集群里面,作为一个 follower 就可以了,因为这会导致原来的所谓大多数不再是大多数。节点中的其他节点并不知道有新节点的加入。
Leader 先向新节点同步数据
Leader 将新节点配置作为一个日志,复制到每个节点中,包括新节点,然后本地提交
每次变更都是单个节点加入
这样就不会存在新旧配置的两个大多数,来保证集群中不会出现两个领导者。