概述
分布式系统作为一致性协议较为常用的有两种:raft协议和paxos 协议。两种协议实现的复杂度不同,paxos相对于raft的复杂难度要高出好几个级别,而目前只有zookeeper实现了paxos的简化版本;而使用raft协议的中间件则相对多很多,例如:etcd和consul。raft协议中有三种角色:Leader、Follower和Candidate,类似于现实中的选举体制,所有角色都需要投票,当一个节点票数过半时,则它会成为leader。
算法细节
在极简的思维下,一个最小的 Raft 民主集群需要三个参与者(如下图:A、B、C),这样才可能投出多数票。初始状态 ABC 都是 Follower,然后发起选举这时有三种可能情形发生。下图中前二种都能选出 Leader,第三种则表明本轮投票无效(Split Votes),每方都投给了自己,结果没有任何一方获得多数票。之后每个参与方随机休息一阵(Election Timeout)重新发起投票直到一方获得多数票。这里的关键就是随机 timeout,最先从 timeout 中恢复发起投票的一方向还在 timeout 中的另外两方请求投票,这时它们就只能投给对方了,很快达成一致。选出 Leader 后,Leader 通过定期向所有 Follower 发送心跳信息维持其统治。若 Follower 一段时间未收到 Leader 的心跳则认为 Leader 可能已经挂了再次发起选主过程。
当一个集群处于就绪状态(即leader已选出时),则客户端可以向集群提交数据,所有的数据提交都会先转发到leader,当 Client 向集群 Leader 节点提交数据后,Leader 节点接收到的数据处于未提交状态(Uncommitted),接着 Leader 节点会并发向所有 Follower 节点复制数据并等待接收响应,确保至少集群中超过半数节点已接收到数据后再向 Client 确认数据已接收。一旦向 Client 发出数据接收 Ack 响应后,表明此时数据状态进入已提交(Committed),Leader 节点再向 Follower 节点发通知告知该数据状态已提交。
脑裂问题
首先先解释下脑裂:脑裂是指一个集群中有两个leader。发生这种现象通常是因为:原先的leader因为网络原因和follower 无法通信,出现了网络分区,这时候follower重新选取一个新的leader,当原先的leader网络恢复,会发现集群中有一个选举轮次更新的leader则他会自动降级成follower。但是如果在它降级为follower之前有client去访问它获取数据则会拿到错误的数据,这是该如何解决?网络分区后,拥有多数节点的分区会继续工作,其它分区暂停工作;如果没有多数节点的分区,则都不工作(即不写入也不会返回查询数据)
参考:https://blog.youkuaiyun.com/z69183787/article/details/103880551