对Primary-backup分布式数据库分布式一致性的猜想

昨天读了paxos算法,心里对分布式一致性有一些想法:如果是我,应该怎么实现数据库集群的一致性呢?

paxos算法本身并没有提到其应用,所以实际使用情况应该较复杂。而我平时接触到使用分布式一致性算法的就是mongodb replicaset。它和zookeeper相似,只是它的data model不只包括集群配置,还有其庞大复杂的数据库。

paxos为何需要两阶段?也许是在learn的时候方便直接使用?也许是。

典型的这种同步做法是,开始时先在集群中选出leader,这个阶段,可能每个节点都可以提出proposal,集群噪音大干扰多效率低;等选出leader后,leader成为唯一的proposer,这样集群中没有proposer互相干扰,写效率提高。

在选master阶段,每个节点都可能提请求,噪音大,不容易达成高度的一致,majority只要超过一半就可以,这样可以减少选leader的时间(这里可靠性也不用过多考虑,如果这个master选举结果的acceptance刚好变得低于majority,那重新选举也无所谓,除非你要对master的变更进行记录,不允许有大概率的丢失)。选了master之后,为了保证系统可靠性,写时majority越大越好,读时majority超过一半就可以。

印象中mongodb选master只需要一次请求就行(貌似slideshare上的mongo讲义上看的),只要提出请求等待被accept就行,如果它得到多数回应接受,它就成为新的master(如果多数都回应了acceptance,但是它不知道,那么它就不是master,是master的条件是它已经知道,如果它不知道它就一直询问直到得到多数回应),它向所有node发出通知自己是master。对于每个数据写请求,通过master发送给所有node之后,收到大多数的acceptance后master才认为写入成功,它发出通知最新版本是oplogid,没有更新到最新的node就从server拿数据。如果发现master挂了(或者连接超时)而能连上多数节点,就发出一个选举自己当master的提议,收到多数acceptance(acceptor只有在连不上原来master的情况下才同意)才认为自己已经是master,它发出通知它已经是master了,得到多数节点"知道了"的回应(这些节点就停止接收旧master的数据),然后它向集群中的节点查询最新版本,根据多数回应决定它需要同步多少数据,选择一个它认为的包含最新版本的节点,同步好这些数据之后它就开始处理新的写请求了。

需要特别说明的是,对于数据写,master可能不知道大多数是否已经写成功,如果无法确知它会一直询问,直到得到多数回应。只有样它才进行后面的写操作。注意还有一个majority的问题,要等待数据写成功的majority应该要设置得比集群一半大一些,比如21个节点的集群,11个就已经超过一半,但写成功的等待比如超过15台才觉得合适。因为如果只是设成11,这11台当时写成功了,但过了一会有一台挂了等于没构成多数,还是没写成功。因此等majority写成功不意味着一定写成功了(理论上只有集群中每个节点都写成功才算成功),但是这个majority设得高一些,成功率可以接近100%。而查询状态的majority只要超过1半就行。

上述系统由于需要很多通信完成同步,要求节点之间延迟较低,在master选择之后,写操作全由master发起,写性能比较差,节点越多写得越慢(扩展性不好),读操作象zookeeper那样从本地读取。zookeeper中切换server节点,不允许切到更低版本的server,这点在web上很有用。你总是要看更新的状态,不能刷新一下回到过去的状态。mongodb的java driver似乎没有做这个工作。


===== 8.27 补记

选好master之后:

一阶段看起来足够了,但是有一点不足,每个节点上对自己的acceptance都不确定是不是集群中已经成功的改动,读取操作时必需要查询一下,这降低了读效率,如果要实现本地读取,就需要使用两阶段request,第一阶段也算是写,只是没有commit,如果这是client读取操作,不会读取这个proposal的修改结果,如果master没有收到足够多的promise,它可以发出回滚的请求,让其他节点放弃修改。第二阶段就是commit了。一旦commit,就可以本地读取了。我们来考虑一下系统的可靠性:

只要集群中有一点包含一个acceptance,这个acceptance就被认为是有效的,第一阶段如果收到多数的promise,而第二阶段之后这个acceptance失效,原因只能是多数节点在一个时间段都挂了,这个概率非常低,多数值设得越大则越低,比一阶段的失败概率低,因而更可靠,并且一旦出现这种问题,系统中多数节点都挂掉已经进入不可用状态,错误不会被覆盖而可以恢复,这一点非常好。(第二阶段request如果没有收到回应,应该不停尝试,错误恢复时节点应该可以回到之前的状态)


选master时 :

两阶段算法中,一个acceptance不代表是集群的master状态,因为同时存在不同的acceptance,因此master状态不能本地读取,集群的状态通过多数情况来决定,因此没有额外的好处,用一阶段应该就够了。


选master和数据库修改的差别在于,master的改动不依赖于之前的master是什么,数据库的状态依赖于之前的状态。

你可能感兴趣的:(mongodb,zookeeper,paxos,分布式一致性)