目录
1、什么是curator?
Apache curator是Apache ZooKeeper(分布式协调服务)的Java/JVM客户端库。它包括一些高级API框架和实用程序,让开发人员使用Apache ZooKeeper更加容易和可靠。它还包括常用用例和扩展的方法,如服务发现和Java 8异步DSL。
2、使用教程
注意:使用zookeeper自己开发的curator,加锁、释放锁的代码完成不用自己造轮子,拿起来用即可,而且不用考虑下游服务超时导致锁已经释放的问题
1.1、引用一下jar包
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>5.2.0</version>
</dependency>
1.2、具体代码
package cn.gt.dl.zookeeper.lock;
import com.alibaba.fastjson.JSONObject;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.ACLProvider;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* @author yanshao
* @date 2022/10/25 5:42 下午
*/
public class ZkExample {
//zk curator client
private CuratorFramework curatorFramework;
//计数器
private final CountDownLatch countDownLatch = new CountDownLatch(2);
@Before
public void curatorFramework() {
String id = "admin:test";
String idScheme = "auth";
String authScheme = "digest";
String connectString = "127.0.0.1:2181";
String connectionTimeoutMs = "60000";
String baseSleepTimeMs = "3000";
String maxCloseWaitMs = "5000";
String maxRetries = "3";
String sessionTimeoutMs = "1000";
ACLProvider aclProvider = new ACLProvider() {
private List<ACL> acl;
@Override
public List<ACL> getDefaultAcl() {
if (null == acl) {
ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
acl.clear();
acl.add(new ACL(ZooDefs.Perms.ALL, new Id(idScheme, id)));
this.acl = acl;
}
return acl;
}
@Override
public List<ACL> getAclForPath(String path) {
return acl;
}
};
//为了保证zookeeper中的数据的安全性,避免误操作带来的影响。
//Zookeeper提供了一套ACL权限控制机制来保证数据的安全。
CuratorFramework curator = CuratorFrameworkFactory.builder()
.aclProvider(aclProvider)//防止其它操作误操作节点,加上权限限制
.authorization(authScheme, id.getBytes())//防止其它操作误操作节点,加上权限限制
.connectString(connectString)//zk连接串
.sessionTimeoutMs(Integer.parseInt(sessionTimeoutMs))//session 超时时间
.connectionTimeoutMs(Integer.parseInt(connectionTimeoutMs)).defaultData("0".getBytes())//连接zk超时时间
.retryPolicy(new ExponentialBackoffRetry(Integer.parseInt(baseSleepTimeMs), Integer.parseInt(maxRetries)))//连接zk重试次数以及重试间隔时间
.maxCloseWaitMs(Integer.parseInt(maxCloseWaitMs))//关闭连接等待时间
.build();
curator.start();
this.curatorFramework = curator;
System.out.println("client已完成初始化");
}
@Test
public void testZkLock() throws InterruptedException {
//两个线程同时抢锁
new Thread(() -> {
try {
businessMethod1();
} catch (Exception e) {
e.printStackTrace();
}
//执行完毕之后,计数器减1
countDownLatch.countDown();
}).start();
new Thread(() -> {
try {
businessMethod2();
} catch (Exception e) {
e.printStackTrace();
}
//执行完毕之后,计数器减1
countDownLatch.countDown();
}).start();
//等待两个线程全部完成
countDownLatch.await();
}
public void businessMethod1() throws Exception {
InterProcessMutex lock = null;
try {
String lockKey = "listened_node";
System.out.println("businessMethod-1>>>开始获取锁");
lock = lock(lockKey);
System.out.println("businessMethod-1>>>已获取锁");
TimeUnit.SECONDS.sleep(10);
} finally {
if (Objects.nonNull(lock)) {
//释放锁
lock.release();
System.out.println("businessMethod-1>>>锁已释放");
}
}
}
@Test
public void businessMethod2() throws Exception {
InterProcessMutex lock = null;
try {
String lockKey = "listened_node";
System.out.println("businessMethod-2>>>开始获取锁");
lock = lock(lockKey);
System.out.println("businessMethod-2>>>已获取锁");
TimeUnit.SECONDS.sleep(20);
} finally {
if (Objects.nonNull(lock)) {
lock.release();
System.out.println("businessMethod-2>>>锁已释放");
}
}
}
private InterProcessMutex lock(String lockKey) throws Exception {
//临时顺序节点的根节点
String lockPath = "/lock1/" + lockKey;
//申明可重入锁
InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
//这里的acquire方法是阻塞方法,超时时间是3分钟
if (lock.acquire(3, TimeUnit.MINUTES)) {
System.out.println("节点列表>>>" + lock.getParticipantNodes());
Stat stat = curatorFramework.checkExists().forPath(lockPath);
if (null != stat) {
System.out.println(lockPath + "节点信息>>>" + JSONObject.toJSONString(stat));
}
}
//返回lock,说明成功获取到锁
return lock;
}
}
运行结果:
代码有较详细的注释,核心代码就这三行,curator完全封装好了,我们只需要“傻瓜”式的使用,而且curator fluent风格的api,也非常OK。