zookeeper分布式锁原理及实现
前言
写zookeeper分布式锁之前,先说下CAP理论吧
C 一致性、A 可用性、P分区容错性。三者不能同时存在,由于P是必要因素,所以分为CP和AP两种模型
前段时间写了redis怎样实现分布式锁,redis实现分布式锁效率是比较高的,但是什么事情都是相对性的,因为redis支持了 AP那么就放弃了CP。
当我们对一致性要求特别高的时候,就需要考虑一种别的分布式锁技术了,
zookeeper因为它集群的选举和同步机制,使得它是支持CP,而放弃了AP,接下来来看看zookeeper是怎么实现分布式锁的吧。
zookeeper的数据结构

类似liux系统的文件目录结构,根节点是/ 下边有很多的子节点 子节点下边也可以有自己的子节点,这个节点叫做znode,当然除了节点以外每个节点都可以存储数据,今天咱们就来说下节点znode
节点类型
1,持久化目录节点–客户端与zookeeper断开连接后,该节点依旧存在
2,持久化顺序目录节点–客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
3,临时节点–客户端与zookeeper断开连接后,节点被删除
4,临时顺序节点–客户端与zookeeper断开连接后,只是Zookeeper给该节点名称进行顺序编号
5,容器节点–3.5.3新增的特性,没有子节点的容器节点会被清除掉。
6,TTL节点–3.5.3新增的特性,位节点设定了失效时间。具体失效时间却决于后台检测失效线程的轮询频率
分布式锁的实现
分布式锁的实现就是根据临时顺序节点这个点来实现的
具体步骤如下
1、每个线程都会在zookeeper中的一个持久节点生成一个临时顺序节点
2、然后判断自己的节点是不是当前顺序最靠前的
3、如果是那么获取到锁,如果不是那么监视它上一个临时顺序节点
4、获取到锁的线程执行完逻辑后,删除当前节点
Curator是Netflix公司开源的一个Zookeeper客户端,Curator框架在zookeeper原生API接口上进行了包装,大大降低了我们操作zookeeper的复杂度,下面来看下Curator是怎么实现的分布式锁
依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
代码如下
//这段代码放在启动类用于初始化Curator客户端
public CuratorFramework getZkClient() {
String zkServerAddress = "127.0.0.1:2181";
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);
CuratorFramework zkClient = CuratorFrameworkFactory.builder()
.connectString(zkServerAddress)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
zkClient.start();
return zkClient;
}
@Service
public class testService {
@Resource
private CuratorFramework zkClient;
//操作库存业务
public String stock() {
String lockPath = "/lock1";
//在根节点上创建lock1节点
InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);
try {
//加锁 这块参数2000代表时间,后边单位,代表线程等待时间,如果传-1代表永久等待
boolean flag=lock.acquire(2000, TimeUnit.SECONDS);
if (flag) {
//操作库存业务
return "";
} else {
return "业务繁忙请稍后重试";
}
} catch (Exception e) {
e.printStackTrace();
return "";
} finally {
//解锁
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果对redis分布式锁感兴趣的请点击redis分布式锁实现
欢迎大家一起交流一起学习,风里雨里我在这里等你