1.zookeeper简介
zookeeper是一个分布式协调服务
应用场景:1.维护服务配置信息 2.分布式锁 3.集群管理 4.生成分布式唯一ID
2.zookeeper实现分布式锁的原理
大概步骤:当客户端需要获取锁,那么创建节点;释放锁,那么删除节点。
具体步骤:
- 客户端获取锁时,在lock节点下创建 临时顺序 节点。
- 然后获取lock节点下的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建节点的序号最小,那么就认为客户端获取到了锁,使用完锁之后将该节点删除。
- 如果发现当前节点序号不是最小,说明当前客户端没有获取到锁,那么当前客户端启动一个监听器去监听比自己序号小的节点的删除事件,监听到删除事件之后回到步骤2继续执行。
3.代码实现
上面的步骤是实现原理。使用apache开源的curator框架,我们只需要少量的代码即可。
- 导入maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
- 代码实现示例
/**
* 测试使用zookeeper作为分布式锁
*/
public class TestDistributionLock {
public static void main(String[] args) {
// 创建资源
Ticket ticket = new Ticket(15);
// 模拟分布式环境
new Thread(ticket, "1号窗口").start();
new Thread(ticket, "2号窗口").start();
}
}
class Ticket implements Runnable {
private int ticketCount;
private final InterProcessLock lock;
public Ticket(int ticketCount) {
this.ticketCount = ticketCount;
// 重试策略
RetryOneTime retryOneTime = new RetryOneTime(2 * 1000);
// 创建zookeeper客户端
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.31.70:2181", retryOneTime);
client.start();
// 指定 /lock 作为锁的根节点
lock = new InterProcessMutex(client, "/lock");
}
@Override
public void run() {
while( ticketCount > 0 ) {
//获取锁
try {
lock.acquire();
if (ticketCount > 0) {
// 为了演示效果,这里增加一个延迟
TimeUnit.MILLISECONDS.sleep(500);
ticketCount--;
System.out.println(Thread.currentThread().getName() + "售出1张票, 当前余票:" + ticketCount);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放锁
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
zookeeper命令行客户端查看 /lock 节点
# 运行中 有两个有编号的顺序节点
[zk: localhost:2181(CONNECTED) 203] ls /lock
[_c_bd193c84-2598-4c36-9a89-a6a2c1056491-lock-0000000013, _c_e00572e7-d355-4388-8e49-54e8bf513bf6-lock-0000000014]
# 运行结束 节点为空
[zk: localhost:2181(CONNECTED) 204] ls /lock
[]
本地控制台
1号窗口售出1张票, 当前余票:14
2号窗口售出1张票, 当前余票:13
1号窗口售出1张票, 当前余票:12
2号窗口售出1张票, 当前余票:11
1号窗口售出1张票, 当前余票:10
2号窗口售出1张票, 当前余票:9
1号窗口售出1张票, 当前余票:8
2号窗口售出1张票, 当前余票:7
1号窗口售出1张票, 当前余票:6
2号窗口售出1张票, 当前余票:5
1号窗口售出1张票, 当前余票:4
2号窗口售出1张票, 当前余票:3
1号窗口售出1张票, 当前余票:2
2号窗口售出1张票, 当前余票:1
1号窗口售出1张票, 当前余票:0
Process finished with exit code 0