ZooKeeper 分布式锁
分布式锁
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致性,在这种情况下,就需要使用分布式锁了。
平常使用的都是数据库中的表锁或者行锁,但是目前绝大多数大型分布式系统的性能瓶颈都集中在数据库操作上。使用ZooKeeper实现分布式锁即可减轻数据库的此方面的压力。
- 排他锁
即写锁或独占锁。如果一个事务 T1对数据对象 O1加上了排他锁,那么在整个加锁期间,只允许事务 T1对 O1进行读或者写操作,只有T1释放了这个排他锁,其他事务才能再对这个对象进行读或写操作。
使用ZooKeeper怎么实现排它锁:
定义锁:通过 ZooKeeper 上的数据节点来表示一个锁,在某指定节点下创建一个子节点
获取锁:所有的需要获取锁的客户端都会试图通过调用 create()接口,在指定节点下创建临时子节点来定义一个锁。ZooKeeper 会保证在所有的客户端中,最终只有一个客户端能够创建成。那么只有创建成功的客户端获取了锁。同时所有没有获取到锁的客户端就需要到代表锁的节点上注册一个子节点变更的Watcher监听,以便实时监听到锁节点的删除,再投入到锁的竞争中去。
释放锁:当前获取锁的客户端机器发生宕机,那么ZooKeeper上的这个临时节点就会被移除。正常执行完业务逻辑后,客户端就会主动将自己创建的临时节点删除。这时所有客户端在该锁节点注册了Watcher监听后得到相应事件,又重新发起分布式锁获取 - 共享锁
读锁,如果事务T1对数据对象O1加上了读锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个对象加共享锁。一直到没有读锁的存在才能去添加写锁。
使用ZooKeeper来实现共享锁。
定义锁:通过 ZooKeeper 上的数据节点来表示一个锁,是一个临时顺序节点
获取锁:在需要获取共享锁时,所有客户端都会到指定节点下面创建一个临时顺序节点,如果当前是读请求,那么就用节点名字创建一个标识读锁或者写锁的临时顺序节点(比如用R标识读,用W标识写,后面跟上顺序的后缀)。
有一下几个步骤,如何判断自己获得了锁:
1.创建完节点后,获取指定节点下的所有子节点(即代表读写锁),并对该节点注册子节点变更的Watcher监听。
2…确定自己的节点序号在所有子节点中的顺序。
3.对于读请求:所有比自己序号小的子节点都是读请求,或者自己是最小的,那么表明自己已经成功获取到了共享锁,同时开始执行读取逻辑,但凡有比自己序号小的子节点中有写请求,那么就需要进入等待。
4.对于写请求:如果自己不是序号最小的子节点,那么就需要进入等待。
5.接收到Watcher通知后,重复步骤2。
释放锁当前获取锁的客户端机器发生宕机,那么ZooKeeper上的这个临时节点就会被移除。正常执行完业务逻辑后,客户端就会主动将自己创建的临时节点删除。这时所有客户端在该锁节点注册了Watcher监听后得到相应事件,重复步骤2开始竞争锁。
再说下以上的优化
在这整个分布式锁的竞争过程中,大量的“Watcher 通知”和“子节点列表获取”两个操作重复运行,并且绝大多数的运行结果都是判断出自己并非是序号最小的节点,从而继续等待下一次通知。
每个锁竞争者,只需要关注指定节点下序号比自己小的那个节点。如果无法获取共享锁,对比自己小的那个节点注册Watcher。
读请求:向比自己序号小的最后一个写请求节点注册Watcher监听。
写请求:向比自己序号小的最后一个节点注册Watcher监听。
还没有评论,来说两句吧...