最近因为想深入分布式方面的理解,所以把paxos协议做了一些理解,查阅了一些文档,写了一个简单的验证代码。
- paxos解决什么问题?
一个集群,无论这个集群的目的是为了负载均衡,还是容错,都需要保证一致性,即保证集群的使用者使用这个集群中的任何一部分,都可以产生预期的相同的结果,所以具体来说就是数据,状态,流程等的一致性。
- 怎么实现?
为了一致性,集群里面的这些节点之间需要互相之间保持沟通,就某个值(来自上面所说的数据,状态,流程)协商,使用的策略就是“少数服从多数”,最简单的情况,选出一个leader(选择leader的方法有很多,最简单的比如每个节点对比考察的ID号,如果是集群里所有ID号里面最小的,就是leader了,当然前提是每个ID在集群中是唯一的),然后这个leader会进行下面的流程:
- 和其它节点(可能包括自己)先通下气,看有多少节点能够投票;
- 明确目前要投票的值;
- 如果可以投票的节点多于集群总节点的一半,那么就把值发给多于一半的节点;
- 其它节点收到之后,如果联络通道还是通畅的,就回复赞成消息给leader;
- leader收到之后,汇总结果,如果投票的还是多于一半,那么就发送给所有的节点,某个值投票通过。
- 其它节点(包括leader本身),收到消息,将此时一致的值记录下来。
但这个是最理想的情况,分布式环境中的程序,需要应对很多在一定的范围内故障(超出一定范围,比如一个集群完全分隔成两个完全隔绝的集群,当然是无法一致的)。paxos的设计应对的故障有:
- 因为通讯,节点故障,选取leader的机制等原因,某个时候有多个leader来尝试发起投票;
- 因为通讯,节点故障,重启,消息有丢失,有重复,有乱序,但消息不能错误,如果节点之间用错误的消息来欺骗,那么也会出错,所以通讯加密,验证,还是重要的。
对第1个方面,主要的处理就是在上面的第1-2步骤,见知乎的回答:
对第2个方面,主要的处理就是:
- 持久化一些数据和状态,在节点重新加入或者新的节点加入的时候,可以很快恢复到最新的状态(比如已经通过的值,正在协商的状态),然后继续处理。
- 通过投票编号过滤重复消息,为某一个没有通过的值多次投票,乱序的问题似乎比较棘手,笔者自己还有未解的疑问。
关于简单的代码验证:
主要参考“参考”中的2论文,暂时没有考虑一些故障,主要是验证上面所述的单个和多个leader同时发起投票的竞争流程,还有从过去轮的投票历史中选择本轮投票的值的流程,python编写,每个线程模拟一个节点,线程之间通过两个单向的queue来通信。
参考:
- https://github.com/papers-we-love/papers-we-love/blob/master/distributed_systems/paxos-made-simple.pdf
- http://research.microsoft.com/en-us/um/people/lamport/pubs/lamport-paxos.pdf
- https://www.zhihu.com/question/19787937/answer/82340987