zookeeper分布式一致性——Paxos算法

	搭建HA集群的时候需要先安装zookeeper,而zookeeper的作用就是保持分布式一致性,它是如何保持分布式一致性的呢?接下来做一个具体了解。
	说到zookeeper我们不得不提及Paxos,因为可以说Paxos是Zookeeper的灵魂。Paxos,它是一个基于消息传递的一致性算法,Leslie Lamport在1990年提出,近几年被广泛应用于分布式计算中。Google的Chubby,Apache的Zookeeper都是基于它的理论来实现的,Paxos还被认为是到目前为止唯一的分布式一致性算法,其它的算法都是Paxos的改进或简化。有个问题要提一下,Paxos有一个前提:没有拜占庭将军问题。拜占庭将军问题是指十支部队同时进攻敌人但是存在间谍使他们通信线路不可信导致无法保证消息一致性的问题。就是说Paxos只有在一个可信的计算环境中才能成立,这个环境是不会被入侵所破坏的。

Paxos场景描述

Paxos描述了这样一个场景,有一个叫做Paxos的小岛(Island)上面住了一批居民,岛上面所有的事情由固定数量的议员其中的一进行提议,其他议员投票来决定。每个提议都有一个编号(PID),这个编号是一直增长 的,不能倒退。每个提议都需要超过半数(是大于不是大于等于)的议员同意才能生效。每个议员只会同意大于当前自己编号的提议,包括已生效的和未生效的。如果议员收到小于等于当前编号的提议,他会拒绝,并告知对方: 你的提议已经有人提过了。这里的当前编号是每个议员在自己记事本上面记录的编号,他不断更新这个编号。整个议会不能保证所有议员记事本上的编号总是相同 的。现在议会有一个目标:保证所有的议员对于提议都能达成一致的看法。
现在模仿议会开始运作,所有议员一开始记事本上面记录的编号都是0。有一个议员发了一个提议:将电费设定为1元/度。他首先看了一下记事本,嗯,当 前提议编号是0,那么我的这个提议的编号就是1,于是他给所有议员发消息:“1号提议,设定电费1元/度”。其他议员收到消息以后查自己记事本,自己当前提议编号是0,那么这个提议可接受,于是他记录下这个提议并回复:我接受你的1号提议,同时他在记事本上记录:当前提议编号为1。发起提议的议员收到了超过半数 的回复,立即给所有人发通知:“1号提议生效!”。收到的议员会修改他的记事本,将1好提议由记录改成正式的法令,当有人问他电费为多少时,他会查看法令并告诉 对方:1元/度。
现在看冲突的解决:假设总共有三个议员S1-S3,S1和S2同时发起了一个提议:1号提议,设定电费。S1想设为1元/度, S2想设为2元/度。结果S3先收到了S1的提议,于是他做了和前面同样的操作。紧接着他又收到了S2的提议,结果他一查记事本,咦,这个提议的编号小于 等于我的当前编号1,于是他拒绝了这个提议:对不起,这个提议先前提过了。于是S2的提议被拒绝,S1正式发布了提议: 1号提议生效。S2向S1或者S3打听并更新了1号法令的内容,然后他可以选择继续发起2号提议。

活锁问题

每一次paxos决议都是一个两阶段过程(prepare和accept)。在有多个议员同时提出议题时,有很大概率冲突,每次冲突都会重新执行prepare阶段,网络和性能开销较大。同时paxos协议本身存在活锁问题,有可能导致一个议题始终无法达成一致。为了解决这两个问题,paxos中引入了leader的概念,从多个proposer中选举出一个leader作为提议代表,每个提议都通过leader发出。这样的话,解决了活锁问题。因为此时提议都是通过leader发出,只要leader保证提案ID自增,就可以跳过prepare阶段,直接进行accept阶段(两阶段变为一阶段)。
考虑这样一种情况:
Ai(i=1,2,…,5)都没有接受过任何提案,A1提出编号为n的Prepare请求并发送给其它节点,A2~A5节点接收到A1的Prepare请求后都承诺不再接受编号小于n的提案。但是,在A1还没有发出Accept请求的时候,A2向所有节点发送了编号为n+1的Prepare请求,由于n+1大于n,所以所有节点都承诺不再接受编号小于n+1的提案。当A1提出的编号为n提案发送到各个节点时,每个节点都会拒绝接受编号为n的提案。同样地,在A2的Accept请求还没送到Ai节点时,Ai节点又接受到编号为n+2的Prepare请求并承诺不再接受编号小于n+2的提案,因此A2的提案又无法获得批准。如此循环往复,始终无法批准提案。这就是活锁问题。

引入leader

产生活锁问题的原因在于,无法控制Proposer提出提案的时机,在一轮算法还没执行结束时就提出提案导致前面的提案被撤销。控制提案进度的方法是,选择一个Leader节点,只允许Leader节点提出提案。Leader节点可以将提案保存在队列中,等一个提案批准后再从队列中取出另外一个提案,这就避免了活锁问题。
引入Leader后,Paxos算法似乎变回到了Primary-Secondary模式,值的执行顺序完全由Leader决定。在3.4.0后的Zookeeper的版本只保留了TCP版本的 FastLeaderElection 选举算法。节点状态: 每个集群中的节点都有一个状态LOOKING, FOLLOWING, LEADING, OBSERVING。都属于这4种,每个节点启动的时候都是LOOKING状态,如果这个节点参与选举但最后不是leader,则状态是FOLLOWING,如果不参与选举则是OBSERVING,leader的状态是LEADING。
开始这个选举算法前,每个节点都会在zoo.cfg上指定的监听端口启动监听(server.1=localhost:2888:3888),这里的2888就是这里用于选举的端口。
server.1=localhost:2888:3888的含义: server.1的1代表机器号 2888代表与leader通信使用的端口号,称为通信端口 3888代表选举leader使用的端口号,称为选举端口
分布式模式下,进程都在不台机器上,端口不能重用,三个配置文件的客户端连接端口,通信端口以及选举端口必须不重复。
当一台机器进入Leader选举时,当前集群可能会处于以下两种状态:
a、集群中已存在Leader。
b、集群中不存在Leader。

选举机制

对于集群中已经存在Leader而言,此种情况一般都是某台机器启动得较晚,在其启动之前,集群已经在正常工作,对这种情况,该机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器而言,仅仅需要和Leader机器建立起连接,并进行状态同步即可。
而在集群中不存在Leader情况下则会相对复杂,其步骤如下:
(1) 第一次投票。无论哪种导致进行Leader选举,集群的所有机器都处于试图选举出一个Leader的状态,即LOOKING状态,LOOKING机器会向所有其他机器发送消息,该消息称为投票。投票中包含了SID(服务器的唯一标识)和ZXID(事务ID),(SID, ZXID)形式来标识一次投票信息。假定Zookeeper由5台机器组成,SID分别为1、2、3、4、5,ZXID分别为9、9、9、8、8,并且此时SID为2的机器是Leader机器,某一时刻,1、2所在机器出现故障,因此集群开始进行Leader选举。在第一次投票时,每台机器都会将自己作为投票对象,于是SID为3、4、5的机器投票情况分别为(3, 9),(4, 8), (5, 8)。
(2) 变更投票。每台机器发出投票后,也会收到其他机器的投票,每台机器会根据一定规则来处理收到的其他机器的投票,并以此来决定是否需要变更自己的投票,这个规则也是整个Leader选举算法的核心所在,其中术语描述如下:
vote_sid:接收到的投票中所推举Leader服务器的SID。
vote_zxid:接收到的投票中所推举Leader服务器的ZXID。
self_sid:当前服务器自己的SID。
self_zxid:当前服务器自己的ZXID。
每次对收到的投票的处理,都是对(vote_sid, vote_zxid)和(self_sid, self_zxid)对比的过程。
规则一:如果vote_zxid大于self_zxid,就认可当前收到的投票,并再次将该投票发送出去。
规则二:如果vote_zxid小于self_zxid,那么坚持自己的投票,不做任何变更。
规则三:如果vote_zxid等于self_zxid,那么就对比两者的SID,如果vote_sid大于self_sid,那么就认可当前收到的投票,并再次将该投票发送出去。
规则四:如果vote_zxid等于self_zxid,并且vote_sid小于self_sid,那么坚持自己的投票,不做任何变更。
模拟一下选举过程。首先三号给自己投了一票,然后将给自己投票的信息广播出去,让大家来投自己。四号收到三号来信,根据上述比较三号zxid比四号的大,优先级比四号高,所以四号给三号投一票。五号收到来自三号的投票时,发现三号的zxid比自己的大。所以五号给三号投一票。三号投票完毕。一共三票。
四号开始投票,首先四号先给自己投一票。然后广播给自己投票。三号收到来信,发现四号zxid没有自己大,所以三号不管四号来信。五号收到四号来信,发现自己虽然zxid和四号相同,但是sid比四号大,所以五号也不管四号来信。四号投票完毕,一共一票。
同理五号得到除自己外的四号一票,一共两票。所以此时产生的leader是三号。

zookeeper集群为何是奇数

1、容错
由于在增删改操作中需要半数以上服务器通过,来分析以下情况。
2台服务器,至少2台正常运行才行(2的半数为1,半数以上最少为2),正常运行1台服务器都不允许挂掉
3台服务器,至少2台正常运行才行(3的半数为1.5,半数以上最少为2),正常运行可以允许1台服务器挂掉
4台服务器,至少3台正常运行才行(4的半数为2,半数以上最少为3),正常运行可以允许1台服务器挂掉
但是明显4台服务器成本高于3台服务器成本,6台服务器成本高于5服务器成本。这是由于半数以上投票通过决定的。
2、防脑裂
一个zookeeper集群中,可以有多个follower、observer服务器,但是必需只能有一个leader服务器。
如果leader服务器挂掉了,剩下的服务器集群会通过半数以上投票选出一个新的leader服务器。
集群互不通讯情况:
一个集群3台服务器,全部运行正常,但是其中1台裂开了,和另外2台无法通讯。3台机器里面2台正常运行过半票可以选出一个leader。
一个集群4台服务器,全部运行正常,但是其中2台裂开了,和另外2台无法通讯。4台机器里面2台正常工作没有过半票以上达到3,无法选出leader正常运行。zookeeper服务终止。
一个集群5台服务器,全部运行正常,但是其中2台裂开了,和另外3台无法通讯。5台机器里面3台正常运行过半票可以选出一个leader。
通可以上分析可以看出,为什么zookeeper集群数量总是单出现,主要原因还是在于第2点,防脑裂,对于第1点,无非是成本控制,但是不影响集群正常运行。但是出现第2种裂的情况,zookeeper集群就无法正常运行了。因此集群数量一般都是奇数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值