Zookeeper 实现分布式锁—Curator
说明:此处仅介绍开源框架Curator原理,不过多牵涉源码
Curator 出处:
由apache 开源,GitHub地址:https://github.com/apache/curator
前期知识
持久节点 (PERSISTENT)
默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。
持久节点顺序节点(PERSISTENT_SEQUENTIAL)
所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:
临时节点(EPHEMERAL)
和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除
临时顺序节点(EPHEMERAL_SEQUENTIAL)
顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。
Zookeeper 本身监听功能
zk 本身具有对自己的某个节点进行监听的功能
图例
-
客户端A 与B 对‘my_lock 进行加锁
-
完整过程
总结
其实如果有客户端C、客户端D等N个客户端争抢一个zk分布式锁,原理都是类似的。
- 客户端加锁会创建一个锁节点下的一个接一个的临时顺序节点
- 如果自己不是第一个节点,就对自己上一个节点加监听器
- 只要上一个节点释放锁,自己就排到前面去了,排队机制。
释放
加锁和释放
/**
*client:curator实现的zookeeper客户端
*path:要在zookeeper加锁的路径,即后面创建临时节点的父节点
*/
InterProcessMutex lock = new InterProcessMutex(client, "/locks/my_lock");
lock.acquire(); //加锁
// 业务代码
lock.release(); //释放
使用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,zk感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。
锁方案
InterProcessMutex:分布式可重入排它锁
InterProcessSemaphoreMutex:分布式排它锁
InterProcessReadWriteLock:分布式读写锁
InterProcessMultiLock:将多个锁作为单个实体管理的容器
源码(以InterProcessMutex 为例)
public class InterProcessMutex implements InterProcessLock, Revocable<InterProcessMutex>
{
private final LockInternals internals;
private final String basePath;
// 以加锁的线程为key
private final ConcurrentMap<Thread, LockData> threadData = Maps.newConcurrentMap();
private static class LockData
{
final Thread owningThread;
final String lockPath;
//重入的次数
final AtomicInteger lockCount = new AtomicInteger(1);
private LockData(Thread owningThread, String lockPath)
{
this.owningThread = owningThread;
this.lockPath = lockPath;
}
}
private static final String LOCK_NAME = "lock-";
}