ZOOKEEPER

zookeeper是什么?能干什么 ?
zk是分布式协调服务。可以用来统一配置管理、统一命名服务、分布式锁、集群管理。
zookeeper 数据模型
它很像数据结构当中的树,也很像文件系统的目录。树是由节点所组成,Zookeeper的数据存储也同样是基于节点,这种节点叫做Znode。
znode里面包含了数据,子节点引用,ACL访问权限,以及znode的各种元数据,比如事务ID、版本号、时间戳、大小等等。
znode 名称唯一,命名有规范,类型分4种:持久,顺序,临时,临时顺序。
Zookeeper是为读多写少的场景所设计。Znode并不是用来存储大规模业务数据,而是用于存储少量的状态和配置信息,每个节点的数据最大不能超过1MB。
zookeeper的重要特点:有序、可复制、迅速、
1 有序: ZooKeeper给每个更新贴上一个数字,这个数字反映了所有ZooKeeper事务的顺序,严格的顺序意味着可以在客户机上实现复杂的同步原语。
2 数据可复制,可备份。zookeeper可以快速地搭建一个集群,内部自带了这样的一些工具与机制,我们只需要设置一些配置即可,保证服务可靠,不会成为单点故障。
3 迅速,zk的数据加载在内存中,这意味着zk可以具备高吞吐低延迟的效率,以读取为事务的话尤其快,操作的znode大小限制为1M。
CAP关系
ZooKeeper是个CP(一致性+分区容错性)的,即任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性。也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。
ZooKeeper是分布式协调服务,它的职责是保证数据在其管辖下的所有服务之间保持同步、一致;所以就不难理解为什么ZooKeeper被设计成CP而不是AP特性的了
session 会话机制
1.一个客户端连接一个会话,由zookeeper分配唯一会话id
2.客户端以特定的时间间隔发送心跳以保持会话有效,
3.超过会话超时时间未收到客户端的心跳,则判断客户端无效(默认2倍tickTime)
4.会话中额请求是FIFO(先进先出原则)的顺序执行
Watch监听机制
客户端能在znodes上设置watch,监听znode的变化,包括增删改查,
通过stat path,get path皆可查看:
触发watch事件的条件有4种,create,delete,change,child(子节点事件)
watch的重要特性
1.仅一次性:watch触发后会立即删除,要持续监听变化的话就要持续提供设置watch,这也是watch的注意事项。
2.有序性:客户端先得到watch通知才可查看变化结果。
注意事项
1.仅一次性
2.获取事件和发送watch,获取watch,这些请求有可能存在延时,所以不能绝对可靠得到每个节点发生的每个更改。
3.一个watch对象只会被通知一次,如果一个watch同时注册了多个接口(exists,getData),如果此时删除节点,虽然这个事件对exists和getData都有效,但是watch只会被调用一次
Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。客户端在向Zookeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager当中。当Zookeeper服务器触发Watcher事件后,会向客户端发送通知,客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑。如下图:
 
Zookeeper Service网络结构
                       (Zookeeper架构图)
Leader和各个follower是互相通信的,对于Zookeeper系统的数据都是保存在内存里面的,同样也会备份一份在磁盘上。
如果Leader挂了,Zookeeper集群会重新选举,在毫秒级别就会重新选举出一个Leader。
集群中除非有一半以上的Zookeeper节点挂了,Zookeeper Service才不可用
zk的读写数据
zk读取数据流程
1 写数据,一个客户端进行写数据请求时,如果是follower接收到写请求,就会把请求转发给Leader,Leader通过内部的Zab协议进行原子广播,直到所有Zookeeper节点都成功写了数据后(内存同步以及磁盘更新),这次写请求算是完成,然后Zookeeper Service就会给Client发回响应。
2 读数据,因为集群中所有的Zookeeper节点都呈现一个同样的命名空间视图(就是结构数据),上面的写请求已经保证了写一次数据必须保证集群所有的Zookeeper节点都是同步命名空间的,所以读的时候可以在任意一台Zookeeper节点上。
Zookeeper工作原理
Zab协议
Zookeeper的核心是广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。
Zab(ZooKeeper Atomic Broadcast)原子消息广播协议作为数据一致性的核心算法,Zab协议是专为Zookeeper设计的支持崩溃恢复原子消息广播算法。
Zab协议核心如下:
所有的事务请求必须一个全局唯一的服务器(Leader)来协调处理,集群其余的服务器称为follower服务器。Leader服务器负责将一个客户端请求转化为事务提议(Proposal),并将该proposal分发给集群所有的follower服务器。之后Leader服务器需要等待所有的follower服务器的反馈,一旦超过了半数的follower服务器进行了正确反馈后,那么Leader服务器就会再次向所有的follower服务器分发commit消息,要求其将前一个proposal进行提交。
Zab模式
Zab协议包括两种基本的模式:崩溃恢复和消息广播
当整个服务框架启动过程中或Leader服务器出现网络中断、崩溃退出与重启等异常情况时,Zab协议就会进入恢复模式并选举产生新的Leader服务器。
当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,Zab协议就会退出恢复模式,状态同步是指数据同步,用来保证集群在过半的机器能够和Leader服务器的数据状态保持一致。
当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个服务框架就可以进入消息广播模式。
当一台同样遵守Zab协议的服务器启动后加入到集群中,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
Zookeeper只允许唯一的一个Leader服务器来进行事务请求的处理,Leader服务器在接收到客户端的事务请求后,会生成对应的事务提议并发起一轮广播协议,而如果集群中的其他机器收到客户端的事务请求后,那么这些非Leader服务器会首先将这个事务请求转发给Leader服务器。
 
消息广播
Zab协议的消息广播过程使用是一个原子广播协议,类似一个2PC提交过程。具体的:
ZooKeeper使用单一主进程Leader用于处理客户端所有事务请求,并采用Zab的原子广播协议,将服务器数据状态变更以事务Proposal的形式广播Follower上,因此能很好的处理客户端的大量并发请求。
另一方面,由于事务间可能存在着依赖关系,Zab协议保证Leader广播的变更序列被顺序的处理,有些状态的变更必须依赖于比它早生成的那些状态变更。
最后,考虑到主进程Leader在任何时候可能崩溃或者异常退出, 因此Zab协议还要Leader进程崩溃的时候可以重新选出Leader并且保证数据的完整性;Follower收到Proposal后,写到磁盘,返回Ack。Leader收到大多数ACK后,广播Commit消息,自己也提交该消息。Follower收到Commit之后,提交该消息。
Zab协议简化了2PC事务提交:
去除中断逻辑移除,follower要么ack,要么抛弃Leader。
Leader不需要所有的Follower都响应成功,只要一个多数派Ack即可。
崩溃恢复
一旦Leader服务器出现崩溃或者与过半的follower服务器失去联系,就进入崩溃恢复模式。
恢复模式需要重新选举出一个新的Leader,让所有的Server都恢复到一个正确的状态。
Leader 选举
Leader选举是保证分布式数据一致性的关键所在。当Zookeeper集群中的一台服务器出现以下两种情况之一时,需要进入Leader选举。
a: 服务器初始化启动
b: 服务器运行期间无法和Leader保持连接。
zk在3.4.0之后只保留了 TCP版本的FastLeaderElection选举算法。当一台机器进入Leader选举时,当前集群可能会处于以下两种状态:
c: 集群中已存在Leader。
d: 集群中不存在Leader。
对于集群中已经存在Leader而言,此种情况一般都是某台机器启动得较晚,在其启动之前,集群已经在正常工作,对这种情况,该机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器而言,仅仅需要和Leader机器建立起连接,并进行状态同步即可
重点理解一下集群中不存在Leader的情况。
Zk的Server 状态可分为4种:
1 LOOKING:寻找Leader。
2 LEADING: Leader状态,对应的节点为Leader。
3 FOLLOWING: Follower状态,对应的节点为Follower。
4 OBSERVING:Observer 状态,对应的节点为Observer,该节点不参与Leader 选举
成为Leader的必要条件: Leader要具有最高的zxid;当集群的规模是n时,集群中大多数的机器(至少n/2+1)得到响应并follow选出的Leader。
心跳机制:Leader与Follower利用PING来感知对方的是否存活,当Leader无法相应PING时,将重新发起Leader选举
术语
zxid:zookeeper transaction id, 每个改变Zookeeper状态的操作都会形成一个对应的zxid,并记录到transaction log中。 这个值越大,表示更新越新。
electionEpoch/logicalclock:逻辑时钟,用来判断是否为同一次选举。每调用一次选举函数,logicalclock自增1,并且在选举过程中如果遇到election比当前logicalclock大的值,就更新本地logicalclock的值。
peerEpoch: 表示节点的Epoch。
选举流程:
(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,那么坚持自己的投票,不做任何变更。
 
(3) 确定Leader。经过第二轮投票后,集群中的每台机器都会再次接收到其他机器的投票,然后开始统计投票,如果一台机器收到了超过半数的相同投票,那么这个投票对应的SID机器即为Leader。此时Server3将成为Leader。
由上面规则可知,通常那台服务器上的数据越新(ZXID会越大),其成为Leader的可能性越大,也就越能够保证数据的恢复。如果ZXID相同,则SID越大机会越大
zookeeper的使用场景
1 分布式锁
2 服务注册和发现:利用Znode和Watcher,可以实现分布式服务的注册和发现。最著名的应用就是阿里的分布式RPC框架Dubbo。
3 共享配置和状态信息:Redis的分布式解决方案Codis,就利用了Zookeeper来存放数据路由表和 codis-proxy 节点的元信息。同时 codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy。此外,Kafka、HBase、Hadoop,也都依靠Zookeeper同步节点信息,实现高可用。
总结:
zk是一个分布式协调服务。
znode是最小的模型单元。
zk在CAP理论中是倾向于CP的。
zk支持集群模式,Leader选举算法为tcp的FastLeaderElection。
zk 采用了ZAB协议保证主从节点的数据一致性。
zk主节点负责写入,所有节点都可以读取。
leader 选举:
每一个集群节点的status : looking leader follower observer
Looking:系统刚启动时或者Leader崩溃后正处于选举状态
follower : 小弟
leader : 领导
刚开始启动都为 looking 状态 , 每台机器启动会投自己一票 , 互相选举的时候选(myid和czid(版本最新的)大的)机器 , 1 2 3 4 5 顺序启动 当到3的时候已经半数以上了,所以 4 5 会跟随 1 2 3 投 3 ,所以 leader是3
(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING
(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;
(5)服务器5启动,同4一样当小弟。
参考链接:
原文地址:https://juejin.im/post/5b03d58a6fb9a07a9e4d8f01

发表评论

邮箱地址不会被公开。 必填项已用*标注