前提:zk中有有序节点,临时节点在用户断开连接后,会自动失效,并且客户端可以watch机制,对一个节点目录进行操作的监视,一旦改目录有变化会通知客户端,
排他锁:只有一个客户端能够获得锁
获取锁:客户端通过create()在/exclusive/下创建lock临时节点/exclusive/lock节点,对于同一个节点,zk保证只有一个用户会创建成功,即得到了锁。其他未得到锁的客户端,watch 节点/exclusive
释放锁:持有锁的客户端主动释放锁,其他等待锁的客户端会收到节点的变化,重新开始获取锁
共享锁:类似读写锁
获取锁:
在需要获取共享锁的时候,客户端会在/shared_lock目录下创建有序临时节点(hostname-请求类型-序号)。例如如果是读请求,会创建192.168.0.1-R-001的节点。如果是写请求,会创建192.168.0.1-W-002的节点。
是否获取到锁的判断:
1. 创建完节点后,获取/shared_lock节点下的所有节点,并对该节点注册子节点变更的watcher监听
确定自己的节点序号在所有子节点中的顺序
对于读请求:如果没有比自己序号小的子节点,或者所有比自己序号小的子节点都是读请求,那么表明自己已经获取到了共享锁
如果比自己序号小的子节点中有写请求,那么就需要进入等待
对于写请求:
如果自己不是序号最小的子节点,那么就需要进入等待。
4. 接收到watcher通知后,重复1
释放锁:
与排他锁一致
问题:共享锁中,未得到锁的客户端在watch通知后,都会获取所有节点信息,比较浪费。
改进:
watcher注册在获取锁的第3步中进行:
读请求:向比自己序号小的最后一个写请求节点注册watcher
写请求:向序号比自己小的最后一个节点注册watcher
zk采用推拉式结合:
配置存储:在zk上,选取一个节点放置config文件
集群中没台机器启动初始化阶段,首先会去zk首次读取配置信息,同时会对放置配置文件的节点注册watcher,当以后配置发生变化,会通知客户端
配置文件变更后,zk会通知注册了wathcer的客户端,客户端重新获取配置信息
note:
如上节使用zookeeper来说,watcher机制并不能保证每一次配置的更改都推送给客户端,这种对于应用也是一件无法允许的事情
Watches通知是一次性的,必须重复注册.
发生CONNECTIONLOSS之后,只要在session_timeout之内再次连接上(即不发生SESSIONEXPIRED),那么这个连接注册的watches依然在。
节点数据的版本变化会触发NodeDataChanged,注意,这里特意说明了是版本变化。存在这样的情况,只要成功执行了setData()方法,无论内容是否和之前一致,都会触发NodeDataChanged。
对某个节点注册了watch,但是节点被删除了,那么注册在这个节点上的watches都会被移除。
同一个zk客户端对某一个节点注册相同的watch,只会收到一次通知。即 Watcher对象只会保存在客户端,不会传递到服务端。
另外最主要一点就是zookeeper并不保证每次节点的变化都会通知到客户端,原因是因为当一次数据修改,通知客户端,客户端再次注册watch,在这个过程中,可能数据已经发生了许多次数据修改
####