本文共 4814 字,大约阅读时间需要 16 分钟。
注: 如果同一时间多个子节点变更,会导致ZooKeeper短时间内向客户端发送大量通知,造成较大的性能影响和网络冲击——羊群效应
排他锁,又称写锁或独占锁。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取或更新操作,其他任务事务都不能对这个数据对象进行任何操作,直到T1释放了排他锁。
排他锁核心是保证当前有且仅有一个事务获得锁,并且锁释放之后,所有正在等待获取锁的事务都能够被通知到。实现步骤:
【1】创建一个lock node
【2】客户端lock执行以下方式:【3】客户端unlock调用delete删除掉节点
优点:缺点:
Apache Curator是一个Zookeeper的开源客户端,它提供了Zookeeper各种应用场景(Recipe,如共享锁服务、master选举、分布式计数器等)的抽象封装,接下来将利用Curator提供的类来实现分布式锁。Curator提供的跟分布式锁相关的类有5个,分别是:
Shared Reentrant Lock 可重入锁
Shared Lock 共享不可重入锁
Shared Reentrant Read Write Lock 可重入读写锁
Shared Semaphore 信号量
Multi Shared Lock 多锁
Shared Reentrant Lock,全局可重入锁,所有客户端都可以请求,同一个客户端在拥有锁的同时,可以多次获取,不会被阻塞。它是由类 InterProcessMutex 来实现,它的主要方法:
// 构造方法public InterProcessMutex(CuratorFramework client, String path)public InterProcessMutex(CuratorFramework client, String path, LockInternalsDriver driver)// 通过acquire获得锁,并提供超时机制:public void acquire() throws Exceptionpublic boolean acquire(long time, TimeUnit unit) throws Exception// 撤销锁public void makeRevocable(RevocationListenerlistener)public void makeRevocable(final RevocationListener listener, Executor executor)
Shared Lock 与 Shared Reentrant Lock 相似,但是不可重入。这个不可重入锁由类 InterProcessSemaphoreMutex 来实现,使用方法和上面的类类似。
Shared Reentrant Read Write Lock,可重入读写锁,一个读写锁管理一对相关的锁,一个负责读操作,另外一个负责写操作;读操作在写锁没被使用时可同时由多个进程使用,而写锁在使用时不允许读(阻塞);此锁是可重入的;一个拥有写锁的线程可重入读锁,但是读锁却不能进入写锁,这也意味着写锁可以降级成读锁, 比如 请求写锁 —>读锁 ---->释放写锁;从读锁升级成写锁是不行的。
可重入读写锁主要由两个类实现:InterProcessReadWriteLock、InterProcessMutex,使用时首先创建一个 InterProcessReadWriteLock 实例,然后再根据你的需求得到读锁或者写锁,读写锁的类型是 InterProcessMutex。Shared Semaphore,一个计数的信号量类似JDK的 Semaphore,JDK中 Semaphore 维护的一组许可(permits),而Cubator中称之为租约(Lease)。有两种方式可以决定 semaphore 的最大租约数,第一种方式是由用户给定的 path 决定,第二种方式使用 SharedCountReader 类。如果不使用 SharedCountReader,没有内部代码检查进程是否假定有10个租约而进程B假定有20个租约。 所以所有的实例必须使用相同的 numberOfLeases 值。信号量主要实现类有:
InterProcessSemaphoreV2 - 信号量实现类Lease - 租约(单个信号)SharedCountReader - 计数器,用于计算最大租约数量
调用 acquire 会返回一个租约对象,客户端必须在 finally 中 close 这些租约对象,否则这些租约会丢失掉。但是,如果客户端session由于某种原因比如crash丢掉,那么这些客户端持有的租约会自动close,这样其它客户端可以继续使用这些租约。租约还可以通过下面的方式返还:
public void returnLease(Lease lease)public void returnAll(Collectionleases)
注意一次可以请求多个租约,如果 Semaphore 当前的租约不够,则请求线程会被阻塞。同时还提供了超时的重载方法。
注意:上面所讲的4种锁都是公平锁(fair)。从ZooKeeper的角度看,每个客户端都按照请求的顺序获得锁,相当公平。
Multi Shared Lock 是一个锁的容器。当调用 acquire,所有的锁都会被 acquire,如果请求失败,所有的锁都会被 release。同样调用 release 时所有的锁都被 release(失败被忽略)。基本上,它就是组锁的代表,在它上面的请求释放操作都会传递给它包含的所有的锁。主要涉及两个类:
InterProcessMultiLock - 对所对象实现类 InterProcessLock - 分布式锁接口类 它的构造函数需要包含的锁的集合或者一组 ZooKeeper 的 path,用法和 Shared Lock 相同补充:Redis与Zookeeper实现分布式锁的区别
转载地址:http://sbhli.baihongyu.com/