基础概念
- zxid:zk中的每一个更新操作都被封装成一个事务操作proposal,zxid是事务的唯一标识
- myid:zk中的每一台服务器都有自己的唯一id标识
- epoch:年代,leader每更换一次,年代值就加一
- ZK节点的状态:
LOOKING: 处于选举状态;
LEADING: 处于领导者状态;
FOLLOWING:处于追随者状态;
OBSERVING:处于观察者状态,此状态下的机器无权利投票
ZK的选主流程
ZK集群中只能有一个leader服务器,其他的服务器为follower或observer;
ZK开始选主的时机
- ZK集群启动时
- 当leader下线时;follower与leader保持心跳连接,当follower无法连接到leader时,会判断leader下线,将自身状态改为LOOKING
- 当follower下线导致leader领导的机器少于半数以上时;leader会检查自己lead的follower数量,当数量小于半数以上时,就会将自己挂掉,然后将自己的状态设置为LOOKING,开启重新选举
ZK选主过程
- 每一台服务器将自己的状态设置为LOOKING
- 每一台服务器投票给自己并广播自己的投票,投票内容为(epoch,zxid, myid) epoch为当前epoch值+1,zxid为自己处理的最大的事务id
- 每一台服务器将收到的票与自己持有的票进行PK,当接收的票epoch小于自己的epoch时,直接忽略;当接收的epoch大于自己的epoch时,更新自己的票的epoch并重新投票;当接收的epoch与自己的epoch相等,比较zxid,选择值较大的票,值较大的说明执行的事务多;如果zxid相等,比较myid,myid较大的服务器优先;之后选择胜出的票作为自己的选票并重新投出
- 统计每一台服务器获取的票数,当票数超过半数以上时,该服务器当选为leader,将状态更新为LEADING,其他服务器更新为FOLLOWING;否则重复2~3步
增加机器时
增加的机器状态一开始为OBSERVING,这种状态下的机器不具有投票的权利;直接以当前集群的leader作为leader即可。
脑裂
脑裂是指一个集群中出现了两个leader;出现脑裂后,对数据的写请求便可以发给两个不同的leader,从而导致数据一致性问题。
原因
一种常见的情况是,leader网络与部分follower断开,于是剩下的follower中选举出了新的leader。之后网络恢复,便出现了两个leader。
由此可见,脑裂情况是由于leader网络暂时与follower中断导致的,也就是出现了分区。根据CAP理论,出现了分区§之后,数据一致性©和可用性(A)之间只能选择一个。
zk的应对措施
ZK采用半数以上参与的方式杜绝脑裂情况的出现。简单说来就是ZK集群中必须有半数以上的机器存在,才能正常提供服务,包括选主,假如超过半数的机器宕机或网络中断,那么ZK集群就无法提供服务。
所以ZK选了一致性©而牺牲了可用性。但是ZK严格来说也并不是强一致性模型,ZK的写请求,只需要半数以上的机器被同步即算写入成功。
例如,ZK集群共有5台机器,那么至少要有3台在线才能保证半数以上,于是当有两台机器宕机时,服务便不可用了。
其他应对措施
- 加权机制:给所有的服务器分配权重,当超过一定权重值时即可进行选主。这样无法杜绝脑裂,但是可以增加对机器宕机的容忍性。
- 加锁机制:采用共享资源作为锁,例如redis,能够获取锁的服务器成为leader。
ZK节点数量最好是奇数,因为为了保证半数以上原则,5台机器只能允许2台宕机,6台机器也只能允许2台,多出的那一台并不能为系统的可用性做出贡献,所以没必要是偶数。
ZK如何处理请求
每一个ZK节点均可以处理读请求,但是写请求只能由leader节点处理;
- 当写请求发给follower节点时,follower节点会转发给leader节点
- leader节点接受写请求,将请求封装成一个事务proposal,分配唯一的zxid
- leader对事务进行处理之后,暂不提交,将事务发送到每一个follower的接收队列中
- follower从队列中取出事务执行,结束之后返回ACK。
- leader收到超过半数以上的follower的ack之后,提交事务并向客户端返回ack。同时向follower的队列中发送事务提交消息
- follower将事务提交
整体过程有点类似于二阶段提交,由leader作为协调节点。但是与二阶段提交不同的是,follower执行的事务与leader完全相同,都是完整的事务;而在分布式事务的二阶段提交中,每个服务仅执行事务中的一部分。
参考文献
https://www.cnblogs.com/ZhuChangwu/p/11622763.html
https://blog.51cto.com/kinglab/2447330