个人对Paxos算法学习的笔记
一个数据(可以是数据库记录,一个日志,一条请求等等),在分布式网络中,不管发生什么问题(服务器宕机,网络异常等),天塌地陷紫金锤…也要保证在各个节点一致。
在Paxos算法有三个角色:
Proposer提案者,Acceptor接收者,Learners学习者们。
Proposal提案里包含要选定的Value,那么简单的过程就是:
提案者们提出各自的提案。
接收者们接收所有提案,并选定某个提案,则Value被确认。
数据一致性就是指提案者、接收者、学习者们都一致决定了,那么多个提案里的Value中,就选你这个Value做Value。
Paxos算法讨论的就是,怎么在众多Value中,在众多复杂情况下,去选出这个Value。
抛开学术语言,我们生活化一些,Proposer当做将军,Acceptor当做元老院的元老,Learners当做士兵,提案就是一份攻击敌人的路线图。数据一致性就是在众多进军路线图中选一个,然后所有人都照此执行。
在具体的实现中,一个进程可以同时兼任三种角色,不过在这里我们分开说。
将军怎么知道哪个路线图被选中了?元老批准了哪个路线图,就是哪个。
元老怎么知道哪个路线图被选中了?接受了哪个路线图,就是哪个。
士兵怎么知道哪个路线图被选中了?元老告诉是哪个路线图,就是哪个。
以上可见,元老很重要,因为是他选的路线图。但是如果只有一个元老,他出问题了,那就全玩完了,所以必须有多个元老。
接着我们来解决多个将军+多个元老怎么确定一份路线图的问题。
我们先极端一下,只有一位将军提出了一份路线图,那元老院只能接受它,不然就没后续了。
这就是第一个限定条件:
一个Acceptor必须接受它收到的第一个提案。
但这就接着出问题了,如果:
将军1提了向北的路线图给元老1,元老1接受了。
将军2提了向南的路线图给元老2,元老2接受了。
将军3提了向西的路线图给元老3,元老3接受了。
完全符合第一个限定条件,但是路线图不一致了。所以我们再加第二个限定条件:
一个提案要被过半数的Acceptor接受才是被选定的。
这也表明了:
一个Acceptor可以接受多个提案。
那么提案就不能只是路线图(Value),还要包含提案编号。
接下来,很自然地,在众多路线图中,一旦过半元老选定了一份,那么不管其他将军的提案是什么,所有人都要遵照执行。哪怕这份路线图是少将提出来的,跟元帅提出的不一样,元老院只要选了,元帅也要执行,其他元老也要执行,即:
编号为N,Value为X的提案一旦被选定,编号大于N,且被Acceptor接受的提案,其Value也必须是X。
接着又出问题了:
有2位将军,5位元老。
假设将军2提了编号为1,向北的路线图给1~4位元老,元老5可能拉肚子、请假什么的,没法接受提案。1~4元老选定了这份路线图,因为过半,所以将军2也认为路线图就是向北了。
此时,你说巧不巧,元老5回来了,而将军1也提了一个编号为2,向南的路线图给他。这是元老5接受的第一份路线图,他只能选定。
这就又不一致了。解决方案也很简单,将军你提案之前,看一看有没有路线图被选定了不就得了。如果有路线图被选定了,你就别再提不一样的路线图就是。
那么,将军怎么提交路线图呢?
1、将军1先生成一个提案编号N,发给过半数的元老们。元老们会回复以下信息:
A:OK!我收到了你的提案编号N,放心,如果后面有比你小的提案编号我就不再处理了,你就是最大的。
B:如果元老之前已经接收过众多路线图,就把小于N的路线图中,最大编号的路线图告知将军。
2、将军1接收到过半数元老的回复,那么提案编号N就可以确定了,接着要确定路线图。
如果元老们告诉将军1,现在还没有人提路线图,那么路线图就由将军1来决定。
如果元老们告诉将军1,已经有其他将军提路线图啦,那将军1就从中选出编号最大的路线图作为自己的路线图。
至此,编号、路线图已经确定,发给过半元老,等待批准。
那么,元老怎么接受路线图呢?
相当简单粗暴。
元老1收到将军1发出的提案编号N(将军提交路线图步骤1),
如果之前收到了>N的提案编号,可以无视,也可以告知将军1,你来晚啦,我不会看你的路线图的,别费心了。
如果N是现在收到的最大的提案编号,就可以按照A、B去回复将军1。
元老1收到将军1发出的提案编号为N,向北的路线图,处理方式同上。
总之一句话,
元老只响应最大的提案编号,也只接受最大编号的路线图。
画个图吧:
接着又引出个问题,既然元老你们只能响应和接受编号最大的路线图,那么:
1、将军1提交编号N,过半元老响应OK。
2、将军2提交编号N+1,过半元老也只能响应OK。
3、将军1提交编号为N,向北路线图,但是元老们不接了,因为只能接受编号N+1的提案。
4、将军1的速度比将军2的快,马上提交编号N+2,过半元老也只能响应OK。
5、此时将军2的编号为N+1,向南路线图也到了,但是元老们也不接了,因为只能接受编号N+2的提案。
6、这时候将军2的速度又比将军1的速度快了,马上提交编号N+3…
还有完没完了,元老们说你们涮傻小子呢?!以后你们这些将军,只能有1个人(主Proposer)向我们提交路线图。
这样的话,假设将军1是主将军。他提交的提案编号最大,此路线图就会被选定。如果将军1发现自己这个提案编号N不是最大的,而是将军2的N+1,但是将军2只有这个N+1的编号,却不能提交自己的提案。那么将军1干脆就舍弃编号N的提案,再提个N+2的提案就是,最终肯定会有提案被批准。
问题又来了,怎么选主Proposer?不好意思Paxos的作者莱斯利·兰伯特(Leslie Lamport)根本就没说这个事,在怹老人家看来,这还是个事?在实际情况中,上面说的步骤,其实就卡在4、6步上,但凡有一次,将军提交提案的速度快于其他将军提交更大编号的速度,这事就解决了,怎么就那么寸,每个将军提案的速度永远慢于其他将军提交更大编号的速度?有这巧劲你去买彩票不更好么。
其实选主Proposer也是有办法的,术语叫租约,谁拿到这个租约,谁就是主,到期可以续约,也可以放出来让其他人抢。
大家把这个租约就当成虎符、龙头棍就行。
这就是Multi-Paxos。
具体怎么选,可以参看PaxosLease算法。
最后就是士兵怎么确定路线图了,士兵只能单向接收来自元老院的命令,路线图下发方案有三:
1、元老(M个)选定一个路线图,就通知所有士兵(N个)。
好处:士兵获取消息最及时。
坏处:下发命令的次数M*N。
2、元老(M个)选定一个路线图,告诉一个士兵长(主Learner),再由士兵长告诉其他士兵。
好处:下发命令的次数减少,M+N-1。
坏处:士兵长出问题了,其他士兵也就拿不到路线图了。
3、元老(M个)选定一个路线图,告诉N个士兵长(主Learner集合),再由士兵长们告诉其他士兵。
好处:士兵长越多,越可靠。
坏处:士兵长越多,下发命令的复杂度就越高。