1、简要介绍ZooKeeper
一个分布式的协调服务框架,可以用于解决分布式环境中的常见问题,例如集群管理,统一命名服务、配置管理,分布式锁等。
曾经看过马士兵老师的相关视频,马老师总结了七个字:有头、唯一、数据树
有头,具有唯一的根结点 /
唯一,每个节点都有唯一的路径
数据树,存储在ZooKeeper的数据整体上形成了一颗二叉树
2、ZooKeeper的选举机制
前提:集群的特性:过半存活,过半选举
分为两个阶段:数据恢复阶段和选举阶段
数据恢复阶段:在这个阶段,每个zk服务器找到自己拥有的最大的事务ID(即最新的事务id);
选举阶段:每台zk服务器提交一份选举协议(一个数据包),包含拥有的事务ID,自己的id,一个逻辑时钟值(用于保证同一次选举过程),自己的当前状态。
3、选举过程中的原则
首先比较事务ID,最新的即为Leader,其余Follower;
最后比较选举ID,最大的即为Leader,其余Follower。
扩展:ZooKeeper的事务ID是一个64位的二进制,高32位是Epoch ID,低32位是递增的事务ID。
4、ZK服务器的状态
Looking-选举状态
Leader-领导状态
Follower-从属状态
Observer-观察者状态
注意:Observer的重点是能够同步Leader的数据,并不参与选举,这样可以避免当服务器过多时,导致的选举时间太长的弊端。
5、ZAB(ZooKeeper Atomic Broadcast)
ZooKeeper使用的一种支持崩溃恢复的原子广播协议,类2PC算法。该协议包含可以无限重复的阶段:
1)消息原子广播(保证数据一致性):ZooKeeper使用单一的主进程(Leader服务器)接受并处理客户端的所有事务请求,并利用ZAB的原子广播协议,将变更数据以事务Proposal(提议)的形式广播到所有的Follower(Observer)中;只有过半服务器反馈成功,才再次向服务器分发Commit消息,要求其进行提交
2)领导者选举:集群启动,或者Leader宕机,或者没有过半的服务器与Leader保持正常通信,就会进入领导者选举阶段。在该模式下,会通过选举机制选举新的Leader。新Leader选举成功后,并且过半Follower已和Leader状态同步,服务器就会退出该阶段进入原子广播阶段。
扩展:在一个遵守ZAB协议的新服务器加入集群,如果此时有Leader,新服务器会进入数据恢复,成功后参加到广播中。
在ZooKeeper中,只允许一个唯一的Leader服务器进行事务请求的处理,若其它服务器接收到请求,会将该请求转发给Leader。
6、在ZooKeeper如何防止脑裂问题?
脑裂指的是在一个集群中,存在两个及以上Leader进行广播事务,导致的事务混乱。
ZooKeeper中有个Epoch(时代)机制,每当有新的Leader出现时,Epoch ID就会递增1,就是说,Follower值接受最大的Epoch ID Leader的数据。
7、Observer-观察者状态
当集群过大后,选举机制导致投票成员过多,写入性能下降。因为写入操作至少一半同意,投票的成本随着机器数量的增多而增加。
为此,ZooKeeper中引入了Observer,该状态的节点不参与投票,只监听投票结果,除了这个以外,其它和Follower一致,可以提供读取操作。并且Observer故障后,不会影响ZooKeeper服务的可用性。
8、ZooKeeper的特性
数据一致性:各个机器上的数据是同步的,通过ZAB协议保证;
原子性:事务决议的更新,要么都更新,要么都不做更新;
可靠性:修改后的数据会保留下来,除非有做修改;
实时性:ZooKeeper将数据加载到内存中供用户快速查询;
顺序性:客户端发起请求时,都会跟一个递增的id;
过半性:Paxos的过半性机制,体现在过半选举、过半存活、事务的过半提交。
9、ZooKeeper中的锁
实现思路:
1)指定一个作为锁的znode,用其描述被锁定的实体,成为/leader;
2)为希望获取该锁的客户端创建一个短暂顺序znode,作为锁节点/leader的子节点;
3)在任何时间点上,顺序号最小的客户端获得该锁。
以上实现可能会造成“羊群效应“,就是在大量客户端观察时,同时受到同一个通知,但是最终只能由一个获得锁。为了避免”羊群效应“,只有在前一个客户端销毁时,才通知下一个客户端。
扩展:ZooKeeper带有一个Java语言写的生成级别的锁实现,名为WriteLock,客户端可以很方便的使用它。