Content Table

ZooKeeper 实现分布式锁

在 Java 中使用 ZooKeeper 实现分布式锁可按以下几步进行:

  1. 下载安装 ZooKeeper 3.4.13,参考 本机安装 ZooKeeper 集群 进行安装单机版 ZooKeeper,有必要的时候再安装集群
  2. 引入 Curator 的依赖,它实现了 ZooKeeper 的分布式锁
  3. Java 测试程序

下载安装

参考 本机安装 ZooKeeper 集群

引入 Curator 的依赖

1
compile group: 'org.apache.curator', name: 'curator-recipes', version: '2.12.0'

注意: Curator 和 ZooKeeper 的版本需要对应,否则会报错

Curator 2.x.x: compatible with both ZooKeeper 3.4.x and ZooKeeper 3.5.x

Curator 3.x.x: compatible only with ZooKeeper 3.5.x and includes support for new features such as dynamic reconfiguration, etc.

Java 测试程序

官方文档: http://curator.apache.org/getting-started.html,先演示 Curator 连接 ZooKeeper 并使用分布式锁 InterProcessMutex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void testDistributedLock() throws Exception {
// [1] This will create a connection to a ZooKeeper cluster using default values.
// The only thing that you need to specify is the retry policy. For most cases, you should use:
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(10000, 3));

// [2] The client must be started (and closed when no longer needed).
client.start();

InterProcessMutex lock = new InterProcessMutex(client, "/ebag/lock");

// [3] 获取全局锁
if (lock.acquire(10, TimeUnit.SECONDS)) {
try {
// [4] 业务代码
System.out.println("Do something");
} finally {
// [5] 释放全局锁
lock.release();
}
}

// [6] Close the client
client.close();
}

多线程测试分布式锁,结果 sn 是按顺序输出的,说明锁生效了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static void testZooKeeperThread() {
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(10000, 3));
client.start();
List<Thread> threads = new LinkedList<>();

for (int i = 0; i < 100; ++i) {
threads.add(new Thread(new ZooKeeperRunnable(client, "/ebag/lock")));
}

for (Thread thread : threads) {
thread.start();
}

// client.close();
}

class ZooKeeperRunnable implements Runnable {
public static int sn = 0;
private InterProcessMutex lock;

public ZooKeeperRunnable(CuratorFramework client, String path) {
lock = new InterProcessMutex(client, path);
}

public void run() {
try {
// 获取全局锁
if (lock.acquire(10, TimeUnit.SECONDS)) {
try {
// Thread.sleep(100);
sn++;
System.out.println(sn);
} finally {
// 释放全局锁
lock.release();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

提示: 上面的多线程是同一个 JVM 中的,可以很简单的修改为在多个 JVM 中运行,演示真正的分布式锁的效果,共享资源 sn 可以保存到 Redis,数据库等中。

ZooKeeper 常用命令

  • 创建: create path data: create /foo "Hello"
  • 修改: set path data: set /foo "Vox"
  • 获取: get path: get /foo
  • 删除: delete path: delete /foo
  • 查看: ls path: ls /foo