选举
- 初始时,没有leader,所有节点都是follower,每个follower都有随机生成的选举超时时间。A超时时间到时,角色会从follower变为candidate,将自己的term加1后,给其余节点发送voteRpc,rpc消息中带有logIndex、logTerm。
- 其余follower收到rpc后,会拿rpc的Term跟本地的term比较,如果小于本地的Term,不投票并带回本地的Term;如果等于本地的Term,则不投票;如果大于本地的Term,则更新本地Term并且投票。(不会重复投票,follower投票后,在没有新的Term的情况下,不会给别的节点投票)
- 如果超过半数票,则candidate变更为leader;否则等待下次选举。
- A成为leader后,会发心跳给follower以确保自己的地位。follower收到心跳后,会重置选举超时时间。(心跳间隔应远小于选举超时时间,否则系统就难以达到稳态)
日志
- A成为Leader后,会跟各个follower协商日志。其中leader,维护了commitIndex,即已经提交的日志的index。leader会维护各个follower的matchIndex和lastIndex,协商前,将matchIndex设置为0,lastIndex设置为commitIndex,然后逆序去跟follower匹配,即lastIndex–逐个去跟follower比较,当匹配上时,将matchIndex设置为lastIndex,然后从lastIndex开始同步日志。稳态时,matchIndex == commitIndex,lastIndex==leader的下一条日志条目。
- 客户端写数据时,会先写leader,leader将日志同步到follower,具体流程如下
注意
- 拥有最新数据的节点,选举时可能成为不了Leader,因为最新数据可能没有超过半数。比如A:3;B:2;C:2,虽然A上有最新数据,但是没有过半。
- 即使数据过半,也有可能被覆盖。所以commitIndex推进的条件为:超半数且半数的term跟leader term一样才推进
场景如下:
A | 1,2 | N | 1,2 | Y | 1,2,4 | 1,2,4 | N | 1,3 | |||
B | 1,2 | 1,2 | 1,2 | 1,2 | 1,3 | ||||||
C | 1 | 1 | 1 | 1,2 | 1,3 | ||||||
D | 1 | 1 | 1 | 1 | 1,3 | ||||||
E | 1 | Y | 1,3 | N | 1,3 | 1,3 | Y | 1,3 |