文章目录
- 一、搭建Zookeeper
- 1、下载
- 2、安装启动
- 二、Zookeeper分布式锁简述
- 三、curator客户端使用分布式锁
- 1、curator概述
- 2、curator使用
- 四、测试效果
- 1、几个常见命令
- 1)ls
- 2)stat
- 3)get
- 4)set
- 2、加锁解锁效果
- 3、竞争锁效果
一、搭建Zookeeper
官网地址:https://zookeeper.apache.org/
1、下载
官方下载地址:https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz
2、安装启动
1> 解压
tar -zxvf apache-zookeeper-3.8.0-bin.tar.gz
2> 创建数据存放目录
cd apache-zookeeper-3.8.0-bin
mkdir data
3> 配置文件修改(conf目录下)
cd ../conf
cp zoo_sample.cfg zoo.cfg
# 修改配置文件
vi zoo.cfg
dataDir=/Users/xxx/software/zookeeper/apache-zookeeper-3.8.0-bin/data
4> 启动
cd ../bin
./zkServer.sh start
5> 查看状态
./zkServer.sh status
这里Zookeeper是以standalone单机模式运行;
Zookeeper集群搭建参考文章:https://saint.blog.csdn.net/article/details/117109245。
二、Zookeeper分布式锁简述
Zookeeper实现排他锁的设计思路如下:
-
zk用
/lock
节点作为分布式锁,当不同的客户端到zk竞争这把锁的时候,zk会按顺序给不同的客户端创建一个临时子节点,挂在作为分布式锁的节点下面。 -
假设第一个来到的客户端为A,第二个来到的是B,分布式锁节点下挂的第一个节点就是A(
/lock/_c_A
),B(/lock/_c_B
)紧跟着A,且B会监听着A的生命状态;- 这里B会先获取到
/lock
路径下所有的节点,发现自己的锁节点(/lock/_c_B
)不在第一位,进而监听自己前一位的锁节点(/lock/_c_A
)。
- 这里B会先获取到
-
当A释放锁后A节点会被删除;B监听到A被删除,B可以尝试获得分布式锁了。
-
具体体现为:客户端B获取
/lock
下的所有子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点在第一位,代表取锁成功。 -
如果还有C节点、D节点,他们都只会监听他们前一个节点,即:C监听B、D监听C。
-
三、curator客户端使用分布式锁
Curator提供的InterProcessMutex是分布式锁的实现。acquire()
方法用于获取锁,release()
方法用于释放锁。
1、curator概述
github: https://github.com/apache/curator
官方地址: https://curator.apache.org/
Apache Curator是Apache ZooKeeper(一种分布式协调服务)的Java/JVM客户端库。它包括一个高级API框架和实用程序,使Apache ZooKeeper的使用更加容易和可靠。
2、curator使用
引入curator的maven依赖,或者直接在curator源码中运行下列demo;
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.4.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.8.0</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
/**
* @author Saint
*/
public class LockTest {
public static void main(String[] args) {
//重试策略,定义初试时间3s,重试3次
ExponentialBackoffRetry exponentialBackoffRetry = new ExponentialBackoffRetry(3000, 3);
//初始化客户端
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.sessionTimeoutMs(3000)
.connectionTimeoutMs(3000)
.retryPolicy(exponentialBackoffRetry)
.build();
// start()开始连接,没有此会报错
client.start();
//利用zookeeper的类似于文件系统的特性进行加锁 第二个参数指定锁的路径
InterProcessMutex interProcessMutex = new InterProcessMutex(client, "/lock");
try {
//加锁
interProcessMutex.acquire();
System.out.println(Thread.currentThread().getName() + "获取锁成功");
Thread.sleep(60_000);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//释放锁
interProcessMutex.release();
System.out.println(Thread.currentThread().getName() + "释放锁成功");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
四、测试效果
在测试代码中,加锁成功之后线程会sleep 60s,这期间我们连上zookeeper可以看下效果;
1、几个常见命令
1)ls
ls命令:查看目录下的节点信息
ls [-s] [-w] [-R] path
- -s:显示节点详情,包括状态信息
- -w:添加一个watch监视器
- -R:列举出节点的级联节点
- path:显示某目录下节点/文件
2)stat
stat命令:查看节点状态。
stat [-w] path
- -w:添加watch
- path:查看某目录下节点的状态
3)get
get命令:获取节点/文件内容
get [-s] [-w] path
- -s:查看节点数据以及节点状态信息
- -w:添加一个watch,节点数据变更时,会通知客户端(通知是一次性的)。
4)set
set命令:修改节点内容
set [-s] [-v version] path data
- -s:更新节点数据并显示节点状态信息
- -v 指定数据版本号,如果指定的数据版本号和数据当前版本号不一致,则更新失败。
2、加锁解锁效果
1> 使用zkCli.sh 链接zookeeper
2> 加锁前后、释放锁后效果:
- 加锁后,/lock路径下会多一个临时节点;临时节点的内容为客户端IP
- 释放锁后,/lock路径的临时节点会被删除。
3、竞争锁效果
启动三次测试类 模拟多个并发的效果,idea中进行如下设置:
开启三次这个测试类之后,zookeeper的/lock路径下会有三个节点:
后启动的依赖于前一个启动的测试类释放分布式锁之后,才能获取到分布式锁。