Zookeeper学习笔记(四)分布式锁

来源:互联网 发布:u盘恢复数据多少钱 编辑:程序博客网 时间:2024/06/11 05:16

一、排他锁与共享锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。分为排他锁和共享锁。

排他锁

排他锁(Exclusive Locks, 简称 X 锁),又称为写锁或独占锁,是一种基本的锁类型。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能再对这个数据对象进行任何类型的操作——直到T1释放了排他锁。

共享锁

共享锁(Shared Locks,简称S锁),又称为读锁。允许一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。(《从PAXOS到ZOOKEEPER分布式一致性原理与实践》中6.17节对共享锁的定义描述实在是不严谨,所以不引用了)。

书上对如何利用Zookeeper实现排他锁和共享锁的描述倒是很清晰易懂的。

对于实现排他锁,简单地说就是多个客户端同时去竞争创建同一个临时子节点,Zookeeper能够保证只有一个客户端创建成功,那么这个创建成功的客户端就获得排他锁。正常情况下,这个客户端执行完业务逻辑会删除这个节点,也就是释放了锁。如果该客户端宕机了,那么这个临时节点会被自动删除,锁也会被释放。

流程图如下:



对于共享锁,则麻烦一些,因为涉及到是读操作还是写操作的问题。所有的客户端都会到某个节点,例如:/shared_lock 下创建一个临时顺序节点,如果是读请求,就会创建诸如 /shared_lock/192.168.0.1-R-0000000001 的节点,如果是写操作,则创建诸如 /shared_lock/192.168.0.1-W-0000000001 的节点。是否获取到共享锁,从以下四个步骤来判断:

1、创建完节点后,获取/shared_lock节点下的所有子节点,并对该节点注册子节点变更的watcher监听。

2、确定自己的节点序号在所有子节点中的顺序。

3、对于读请求:

如果没有比自己序号小的子节点,或是所有比自己序号小的子节点都是去请求,那么表明自己已经成功获取到了共享锁,同时开始执行读取逻辑。

如果比自己序号小的子节点中有写请求,那么就需要进入等待。

对于写请求:

如果自己不是序号最小的子节点,那么就需要进入等待。

4、接收到Watcher通知后,重复步骤1。

流程图如下:



二、排他锁的Curator实现

基本摘抄自书上的示例代码:

package com.my.CuratorTest;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;import org.apache.curator.retry.ExponentialBackoffRetry;import java.util.concurrent.CountDownLatch;/** * Title: <br/> * Intention: <br/> * <p> * Class Name: com.my.CuratorTest.RecipesSharedLockTest<br/> * Create Date: 2017/8/20 17:07 <br/> * Project Name: MyTest <br/> * Company:  All Rights Reserved. <br/> * Copyright © 2017 <br/> * </p> * <p> * author: GaoWei <br/> * 1st_examiner: <br/> * 2nd_examiner: <br/> * </p> * * @version 1.0 * @since JDK 1.7 */public class RecipesSharedLockTest {static String lockPath = "/curator_recipes_lock_path";static CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181").retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();static int data = 1;public static void main(String[] args) {client.start();final InterProcessReadWriteLock lock = new InterProcessReadWriteLock(client, lockPath);final CountDownLatch down = new CountDownLatch(1);for (int i= 0;i< 30;i++) {final int k = i;new Thread(new Runnable() {@Overridepublic void run() {if (k%2 == 0) {try {down.countDown();lock.readLock().acquire();System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到读锁,当前数据="+ data);lock.readLock().release();} catch (Exception e) {e.printStackTrace();}} else {try {down.countDown();lock.writeLock().acquire();data ++;System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到写锁,写入成功,当前数据="+ data);lock.writeLock().release();} catch (Exception e) {e.printStackTrace();}}}}).start();}down.countDown();}}


三、共享锁的Curator实现

package com.my.CuratorTest;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;import org.apache.curator.retry.ExponentialBackoffRetry;import java.util.concurrent.CountDownLatch;/** * Title: <br/> * Intention: <br/> * <p> * Class Name: com.my.CuratorTest.RecipesSharedLockTest<br/> * Create Date: 2017/8/20 17:07 <br/> * Project Name: MyTest <br/> * Company:  All Rights Reserved. <br/> * Copyright © 2017 <br/> * </p> * <p> * author: GaoWei <br/> * 1st_examiner: <br/> * 2nd_examiner: <br/> * </p> * * @version 1.0 * @since JDK 1.7 */public class RecipesSharedLockTest {static String lockPath = "/curator_recipes_lock_path";static CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181").retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();static int data = 1;public static void main(String[] args) {client.start();final InterProcessReadWriteLock lock = new InterProcessReadWriteLock(client, lockPath);final CountDownLatch down = new CountDownLatch(1);for (int i= 0;i< 30;i++) {final int k = i;new Thread(new Runnable() {@Overridepublic void run() {if (k%2 == 0) {try {down.countDown();lock.readLock().acquire();System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到读锁,当前数据="+ data);lock.readLock().release();} catch (Exception e) {e.printStackTrace();}} else {try {down.countDown();lock.writeLock().acquire();data ++;System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到写锁,写入成功,当前数据="+ data);lock.writeLock().release();} catch (Exception e) {e.printStackTrace();}}}}).start();}down.countDown();}}


参考:

1、从PAXOS到ZOOKEEPER分布式一致性原理与实践