ZooKeeper 开发随笔

基于 ZooKeeper 实现分布式锁

  • 由于下面使用了 Curator 客户端,因此需要引入相应的依赖
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.5.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.5.0</version>
</dependency>
  • 基于 ZooKeeper 实现分布式锁
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
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class CuratorDistributedLockExample {

private static final String ZOOKEEPER_CONNECTION_STRING = "localhost:2181";
private static final String LOCK_PATH = "/zk-lock";

public static void main(String[] args) throws Exception {
CuratorFramework client = CuratorFrameworkFactory.newClient(ZOOKEEPER_CONNECTION_STRING, new ExponentialBackoffRetry(1000, 3));
client.start();

InterProcessLock lock = new InterProcessMutex(client, LOCK_PATH);
try {
// 获取锁
lock.acquire();
// 在这里执行需要加锁的业务逻辑
System.out.println("Lock acquired, do some work here...");
// 模拟业务逻辑耗时
Thread.sleep(5000);
} finally {
try {
// 释放锁
lock.release();
System.out.println("Lock released.");
} catch (Exception exception) {
exception.printStackTrace();
}
}

client.close();
}
}

在这个示例中,首先创建了 Curator 客户端,然后使用 InterProcessMutex 类创建了一个分布式锁实例。在 try 块中调用 acquire() 方法获取锁,在获取锁后执行需要加锁的业务逻辑,最后在 finally 块中释放锁。Curator 会自动处理加锁、解锁和失败重试等复杂逻辑,简化了分布式锁的使用。

Dubbo 使用 Curator 连接 ZooKeeper 失败

异常日志:

1
Caused by: org.apache.zookeeper.KeeperException$UnimplementedException: KeeperErrorCode = Unimplemented for /dubbo/xxx.xxx.service.UserService/providers/dubbo ....

异常分析:ZooKeeper 的版本与 Curator 的版本不兼容所导致,Curator 官网说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
第一种情况:

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.

第二种情况:

ZooKeeper 3.5.x
Curator 4.0 has a hard dependency on ZooKeeper 3.5.x
If you are using ZooKeeper 3.5.x there's nothing additional to do - just use Curator 4.0

ZooKeeper 3.4.x
Curator 4.0 supports ZooKeeper 3.4.x ensembles in a soft-compatibility mode. To use this mode you must exclude ZooKeeper when adding Curator to your dependency management tool.

解决方法:针对第二种情况,假设各组件的版本分别为 Dubbo (2.7.0)、ZooKeeper (3.4.13)、Curator-Framework (4.0.1),则需要排除 Curator-Framework (4.0.1) 默认依赖的高版本 ZooKeeper (3.5.x),然后指定低版本的 ZooKeeper (3.4.x),Maven 的 POM 写法如下:

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
<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>