节点特性
1.同一级节点key名称是唯一的
2.创建节点时,必须要带上全路径
3.session关闭,临时节点清除
4.自动创建顺序节点
5.watch机制,监听节点变化
6.delete命令只能一层一层删除
应用场景:
1.数据发布/订阅
2.负载均衡
3.分布式协调/通知
4.集群管理
5.master管理
6.分布式锁/队列
zookeeper的ACL(Access Control List)权限可以针对节点设置相关读写等权限,保障数据安全性.permissions可以指定不同的权限范围及角色.
ACL命令行:
getAcl命令:获取某个节点的acl权限信息
setAcl命令:设置某个节点的acl权限信息
addauth命令:输入认证授权信息,注册时输入明文密码,加密形式保存
ACL构成
zookeeper的acl是通过scheme:id:permissions来构成权限列表
scheme:代表采用的某种权限机制,包括world,auth,ip,super等几种.
id:代表允许访问的用户
permissions:权限组合字符串,由cdrwa组成,其中每个字母代表支持不同权限,创建create,删除权限delete,读权限read,写权限write,管理权限admin
watcher事件机制原理剖析:
zookeeper的watcher机制,可以分为四个过程:
客户端注册watcher
服务端处理watcher
服务端触发watcher事件
客户端回调watcher
其中客户端注册watcher有三种方式,调用客户端API可以分别通过getData,exists,getChildren实现,利用前面章节创建的maven工程,新建WatcherDemo类,以exists方法举例说明其原理
1.客户端发送事件通知请求.
在zookeeper类调用exists方法时候,把创建事件监听封装到request对象中,watch属性设置为true,待服务器返回response后把监听事件封装到客户端的zkwatchmanager类中.
2.服务端处理watcher事件的请求
服务端nioservercnxn类用来处理客户端发送过来的请求,最终调用到FinalRequestProcessor,这其中有一段源码添加客户端发送过来的watcher事件,然后进入statNode方法,在DataTree类方法中添加watcher事件,并保存至WatchTable与watchTable中.
3.服务端触发watcher事件流程:
若服务端某个被监听的节点发生事务请求,服务端处理请求过程中调用FinalRequestProcessor类processRequest方法中的代码,删除调用链最终到DataTree类中删除节点分支的触发代码段.进入watchmanager类的triggerWatch方法.继续跟踪进入NIOServerCnxn,构建一个xid为-1,zxid为-1的ReplyHeader对象,然后调用sendResonpe方法.
4.客户端回调watcher时间
客户端sendthread类readresponse方法接收服务端触发的事件通知,进入xid为-1流程,处理Event事件
zookeeper数据同步流程
在zookeeper中主要依赖ZAB协议来实现分布式数据一致性.ZAB协议分两部分:
消息广播
zookeeper使用单一的主进程leader来接受和处理客户端所有事务请求,并采用ZAB协议的原子广播协议,将事务请求以Proposal提议广播到所有Follower节点,当集群中有过半的Follower服务器进行正确的ACK反馈,那么Leader就会再次向所有的Follower服务器发送commit消息,将此次提案进行提交.这个过程可以简称为2pc事务提交,整个流程可以参考下图,注意Observer节点只负责同步Leader数据,不参与2pc数据同步过程.
崩溃恢复:
在正常情况消息广播情况下能运行良好,但是一旦Leader服务器出现崩溃,或者由于网络原理导致Leader服务器失去了与过半Follower的通信,那么就会进入崩溃恢复模式,需要选举出一个新的Leader服务器.在这个过程中可能会出现两种数据不一致性的隐患,需要zab协议的特性进行避免.
1.Leader服务器将消息commit发出后,立即崩溃
2.Leader服务器刚提出proposal后,立即崩溃
ZAB协议的恢复模式使用了以下策略:
1.选举zxid最大的节点作为新的leader
2.新leader将事务日志中尚未提交的消息进行处理
zookeeperLeader选举原理:
zookeeper的leader选举存在两个阶段,一个是服务器启动时leader选举,另一是运行过程中leader服务器宕机.在分析选举原理前,先介绍几个重要参数.
服务器ID:编号越大在选举算法中权重越大
事务ID(zxid):值越大说明数据越新,权重越大
逻辑时钟:同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加
选举状态:
LOOKING:竞选状态
FOLLOWING:随从状态,同步leader状态,参与投票
OBSERVING:观察状态,同步leader状态,不参与投票
LEADING:领导者状态
1.服务器启动时的leader选举
每个节点启动的时候都LOOKING观望状态,接下来就开始进行选举主流程.这里选取三台机器组成的集群为例.第一台服务器server1启动时,无法进行leader选举,当第二台服务器server2启动时,两台机器可以互相通信,进入leader选举过程.
(1)每台server发出一个投票,由于是初始情况,server1和server2都将自己作为leader服务器进行投票,每次投票包含所推举的服务器myid,zxid,epoch,使用myid,zxid表示,此时server1投票为(1,0),server2投票为(2,0),然后将各自投票发送给集群中其他机器.
(2)接收来自各个服务器的投票.集群中的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch),是否来自LOOKING状态的服务器.
(3)分别处理投票,针对每一次投票,服务器都需要将其他服务器的投票和自己的投票进行对比,对比规则如下:优先比较epoch;检查zxid,zxid比较大的服务器优先作为leader;如果zxid相同,那么就比较myid,myid较大的服务器作为leader服务器
(4)统计投票.每次投票后,服务器统计投票信息,判断是都有过半机器接收到相同的投票信息.server1,server2都统计出集群中有两台机器接受了(2,0)的投票信息,此时已经选出了server2位leader节点.
(5)改变服务器状态.一旦确定了leader,每个服务器响应更新自己的状态,如果是follower,那么就变更为FOLLOWING,如果是Leader,变更为LEADING.此时server3继续启动,直接加入变更自己为FOLLOWING.
2.运行过程中的leader选举
当集群中leader服务器出现宕机或者不可用情况时,整个集群无法对外提供服务,进入新一轮的leader选举.
(1)变更状态.leader挂后,其他非Oberver服务器将自身服务器状态变更为LOOKING.
(2)每个server发出一个投票,在运行期间,每个服务器上zxid可能不同.
(3)处理投票,规则同启动过程
(4)统计投票,与启动过程相同
(5)改变服务器状态,与启动过程相同
zookeeper分布式锁实现原理
分布式锁是控制分布式系统之间同步访问共享资源的一种方式,下面介绍zookeeper如何实现分布式锁,讲解排它锁和共享锁两类分布式锁.
排它锁:
又称为写锁或独占锁,如果事务T1对数据对象O1加上排它锁,那么整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能进行读或写.
实现方式:
利用zookeeper的同级节点的唯一性特性,在需要获取排它锁时,所有的客户端视图通过调用create()接口,在/exclusive_lock节点下创建临时子节点/exclusive_lock/lock,最终只有一个客户端能够创建成功,那么此客户端就获得了分布式锁.同时没有获取到锁的客户端可以在/exclusive_lock节点上注册一个子节点变更的watcher监听事件,以便重新争取获得锁.
共享锁:
又称读锁.如果事务T1对数据对象o1加上了共享锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个数据对象加共享锁,直到该数据对象上的所有共享锁都释放.
实现方式:
1.客户端调用create方法创建类似定义锁方式的临时顺序节点.
2.客户端调用 getChildren 接口来获取所有已创建的子节点列表.
3.判断是否获得锁,对于读请求如果所有比自己小的子节点都是读请求或者没有比自己序号小的子节点,表明已经成功获取共享锁,同时开始执行度逻辑。对于写请求,如果自己不是序号最小的子节点,那么就进入等待.
4.如果没有获取到共享锁,读请求向比自己序号小的最后一个写请求节点注册 watcher 监听,写请求向比自己序号小的最后一个节点注册watcher 监听.
实际开发过程中,可以 curator 工具包封装的API帮助我们实现分布式锁。
curator 的几种锁方案 :
1.InterProcessMutex:分布式可重入排它锁
2.InterProcessSemaphoreMutex:分布式排它锁
3.InterProcessReadWriteLock:分布式读写锁