Curator基于zookeeper实现分布式锁
一、背景
Curator是Netflix公司开源的一个ZooKeeper客户端封装。通过在zookeeper的某路径节点下创建临时序列节点来实现分布式锁。即每个线程(跨进程的线程)获取同一把锁前,都需要在同样的路径下创建一个节点,节点名字由uuid + 递增序列组成。而通过对比自身的序列数是否在所有子节点的第一位,来判断是否成功获取到了锁。当获取锁失败时,它会添加watcher来监听前一个节点的变动情况,然后进行等待状态。直到watcher的事件生效将自己唤醒,或者超时时间异常返回。
由于原生zookeeper实现的分布式锁实现步骤繁琐且不好控制,Curator提供了很好的基于zookeeper的实现,提供了InterProcessMutex(可重入锁)、InterProcessSemaphoreMutex、InterProcessReadWriteLock(读写锁)相关锁的操作。
注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!
二、基于ZooKeeper的实现方式
ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:
(1)创建一个目录mylock;
(2)线程A想获取锁就在mylock目录下创建临时顺序节点;
(3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
(4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
(5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
优点:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。
缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。
三、添加Maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
四、代码实现
package com.lance.net.server;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class CuratorTest {
private static int count=10;
public static void main(String[] args) {
//重试策略 (初始休眠时间为 1000ms, 最大重试次数为3)
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
//zookeeper地址,集群用逗号分隔(127.0.0.1:2181,27.0.0.1:2182)
String connUrl="127.0.0.1:2181";
for (int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
CuratorFramework zk=CuratorFrameworkFactory.newClient(connUrl,retryPolicy);
zk.start();
//可重入锁,即是获锁后,还可以再次获取
InterProcessLock lock=new InterProcessMutex(zk,"/lock");
try {
//获得锁
if( lock.acquire()){
get();
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//释放锁
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
public static void get() throws InterruptedException {
count--;
if(count==3){
Thread.sleep(2000);//这里设置该线程睡眠2秒,已达到锁住效果
}
System.out.println(count);
}
}
五、关键点说明
-
CuratorFramework对象创建方式
第一种创建方式,通过newClient创建对象
CuratorFramework zk=CuratorFrameworkFactory.newClient(connUrl,retryPolicy);第二张创建方式,通过builder()创建对象
CuratorFramework zk=CuratorFrameworkFactory.builder()
.connectString(connUrl)
.sessionTimeoutMs(2000)
.retryPolicy(retryPolicy)
.build(); -
锁对象的说明
//可重入锁,即是获锁后,还可以再次获取
InterProcessLock lock=new InterProcessMutex(zk,"/lock");// 不可重入锁,即是获锁后,不可再次获取
InterProcessLock interProcessLock = new InterProcessSemaphoreMutex(zk,"/lock");//读写锁
InterProcessReadWriteLock lock=new InterProcessReadWriteLock(zk,"/lock");// 创建多重锁对象
// InterProcessLock lock = new InterProcessMultiLock(Arrays.asList(zk,"/lock"));
六、curator的重连策略
curator连接zookeeper服务器时有自动重连机制,而curator的重连策略有五种。
第一种就是我们以上demo中使用到的:
/**
- (推荐)
- 同步创建zk示例,原生api是异步的
- 这一步是设置重连策略
- 构造器参数:
- curator链接zookeeper的策略:ExponentialBackoffRetry
- baseSleepTimeMs:初始sleep的时间
- maxRetries:最大重试次数
- maxSleepMs:最大重试时间
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
第二种,可设定重连n次:
/**
- (推荐)
- curator链接zookeeper的策略:RetryNTimes
- 构造器参数:
- n:重试的次数
- sleepMsBetweenRetries:每次重试间隔的时间
*/
RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
第三种,只会重连一次:
/**
- (不推荐)
- curator链接zookeeper的策略:RetryOneTime
- 构造器参数:
- sleepMsBetweenRetry:每次重试间隔的时间
- 这个策略只会重试一次
*/
RetryPolicy retryPolicy2 = new RetryOneTime(3000);
第四种,永远重连:
/**
- 永远重试,不推荐使用
*/
RetryPolicy retryPolicy3 = new RetryForever(retryIntervalMs)
第五种,可设定最大重试时间:
/**
- curator链接zookeeper的策略:RetryUntilElapsed
- 构造器参数:
- maxElapsedTimeMs:最大重试时间
- sleepMsBetweenRetries:每次重试间隔
- 重试时间超过maxElapsedTimeMs后,就不再重试
*/
RetryPolicy retryPolicy4 = new RetryUntilElapsed(2000, 3000);
七、获得锁以及释放锁的流程
JedisLock基于Redis实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/84977357