Multi-Paxos Raft
前言
分布式一致性算法中鼎鼎有名的Paxos算法,有以下的特点
1、理论上证明了是可靠的
2、但是这个证明,这个原理,是真他喵的难懂😂
3、就算真懂了也很难真正实现
4、有live lock的问题
于是人们实在被搞的烦死了,又发明了另一种Multi-Paxos算法:Raft
Raft,相对于Paxos,特点是:
1、没有理论证明是可靠的
2、容易理解
3、容易实现
4、实践见真知
先看动画学个大概
http://thesecretlivesofdata.com/raft/
看懂了大概流程之后,我们可以在这里面玩一下各种情况下最终怎么保持一致性的:
玩完之后我们来带着一些问题看细节:
当有一个机器挂掉了,落后了好多进度,应该怎么通过这个协议追上来呢?
说明 | 总览图 | leader视角 | follower视角 | 数据包 |
先模拟这个进度落后的情况: 好端端的突然S4掉线了 | 由于S4挂了,leader拿不到信息了,上次记着他的match index=2,next index = 3 | 而我们挂掉的S4保存的信息是:commitIndex=2 | leader给S4发的请求AppendEntries。prevIndex=2, commitIndex=3,entries=[2]
S4知道自己commitIndex=2,然后S1想让S4commitIndex=3,大概意思就是想让S4把3这个entry给填成【2】 | |
然后我们把S4重启 【bring yourself back online 😂】,接收一个来自S1的请求之后 | 然后S1收到了S4的返回,知道S4填好了,就把本地的表给改成S4的match index=3 | |||
如无意外,这么搞下去很快S4就会追上进度了。那就来点意外吧😂让leader挂掉,咱们换个任期。 | ||||
其他人都收不到leader心跳了,会重新选一个leader | S2作为candidate请求大家给自己投票 | |||
随后S5也想当leader | S2想当leader,S3 S4同意,S5不同意 但是已经获得大多数,S2还是成为了leader;而S5无法获得多数,竞选失败。 这个过程中,各个节点如果认可新leader,应该会把自己的log信息汇报给新leader,新leader更新自己的peers表。 |
| ||
在这个战乱的时刻,我们来关注一下进度跟不上的S4, | somehow S4的matchindex归为0了 | |||
然后S4需要向leader汇报自己的进度,最终也就跟上来了 |
我们再简化一下,只有3个机器
说明&总览 | S1 | S2 | S3 |
S3经过投票成为leader,然后接受了2个写请求并同步完成 | follower | follower | leader |
让S1挂掉,S3接受2写请求,S1落后进度,这时候S3发4个请求出去,只有1个回,达不到过半数,数据处于半提交状态。 | 挂掉 | follower | leader |
让S1重新上线,慢慢就恢复了一致性 | follower | follower | leader |
所以这个协议是怎么保证最终的一致性呢,落后进度的情况下,有些节点挂掉的情况下,再重启,怎么就会好了呢?这些都要通过原理来解释
然后参考下面视频看看原理
https://www.bilibili.com/video/BV1wt411y7Da/?spm_id_from=333.788.videocard.0
1、客户端给server发送command
2、server使用paxos协议,选择command
3、server等待前一个log entries被applied,然后apply一个新的command到状态机
4、server状态机的结果给客户端。
解答以下问题:
来了一个客户端请求,要用哪个log entry?
性能优化:
- 选个leader来减少proposer 冲突
- 消除大量的Prepare 请求
保证全部复制好
客户端协议
配置改变
注:这个算法其实没有得到严格的证明,说不定有bug。哈哈哈哈
当客户端的请求到达的时候:
- 找到第一个还没被chosen的logEntry
- 运行basic paxos,propose 客户端的command
- prepare请求返回了acceptedValue?
- yes:选择acceptedValue,重新开始
- no:选择客户端的command
如上图,先假设server3掉线了,client command=jmp,发到了server1;
server1找到最小的not chosen index = 3,运行paxos,prepare请求,发现server1已经acceptedValue=cmp,那就接受index=3:cmp,然后重新开始
server1找到最小的not chosen index = 4,运行paxos,prepare请求,发现server2已经acceptedValue=sub,那就接受index=4:sub,然后重新开始
server1找到最小的not chosen index = 5,运行paxos,prepare请求,没发现acceptedValue,终于可以使用client的command。index=5:jmp
选leader:
有最大的id的人当leader
每Tms 每个server发送心跳给其他server
如果一个server在过去的2Tms 没有收到其他server更高的id,他就成为了leader:
- 可以接受客户端的请求
- 扮演proposer和Acceptor
如果server不是leader
- 拒绝客户端请求,转发给leader
- 只能当Acceptor
消除Prepares
为什么需要prepare?
- 用来block掉老的proposal
- 让proposal number代表整个log,而不是一个entry
有点难懂,未完待续。。。。。。。