软件开发 --- Zookeeper 之初体验
使用 Zookeeper 实现一个简单的服务注册与发现功能。
Zookeeper 简介
Zookeeper 是一个分布式协调服务,主要用于分布式系统中的数据共享、状态同步和服务发现等。常见的应用场景包括:分布式锁、配置管理、服务注册与发现等。
1. 安装 Zookeeper
首先,我们需要在本地或服务器上安装 Zookeeper,安装步骤如下:
1.1 下载并解压 Zookeeper
- 访问 Zookeeper 官方网站,下载最新版本的 Zookeeper。
- 解压下载的文件,例如将其解压到
/usr/local/zookeeper
(Linux)或C:\zookeeper
(Windows)目录。
1.2 配置 Zookeeper
Zookeeper 需要配置一个配置文件 zoo.cfg
。在解压目录下,conf
文件夹中有一个模板配置文件 zoo_sample.cfg
,你可以复制一份并重命名为 zoo.cfg
。
cp conf/zoo_sample.cfg conf/zoo.cfg
1.3 配置文件内容(zoo.cfg
)
打开 zoo.cfg
文件并确保以下内容存在(基本配置):
# 设置 Zookeeper 数据存储路径
dataDir=/tmp/zookeeper
# 设置 Zookeeper 服务运行的端口
clientPort=2181
# 启用 Zookeeper 服务器集群模式(如果是单机模式,可以不需要修改)
# server.1=localhost:2888:3888
dataDir
是 Zookeeper 存储数据的目录。clientPort
是客户端连接 Zookeeper 服务的端口,默认是2181
。
1.4 启动 Zookeeper
在命令行中运行以下命令启动 Zookeeper:
bin/zkServer.sh start # Linux/macOS
Windows 用户运行 zkServer.cmd
文件。
你可以运行以下命令来检查 Zookeeper 的状态:
bin/zkServer.sh status # Linux/macOS
2. Java 环境配置
Zookeeper 是一个 Java 应用程序,操作 Zookeeper 需要通过 Java 客户端。
2.1 添加 Zookeeper 依赖
在你的 Maven 项目中,添加以下依赖:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.0</version>
</dependency>
2.2 创建服务注册与发现的 Zookeeper 使用案例
下面,我们实现一个服务注册与发现的案例。假设我们有多个服务,它们会将自己注册到 Zookeeper,其他服务通过查询 Zookeeper 获取服务的地址和端口。
3. Zookeeper 服务注册与发现
我们将演示如何在 Zookeeper 中实现服务的注册和发现。服务注册时,服务会在 Zookeeper 上创建临时节点,而客户端则通过监视这些节点来发现服务。
3.1 服务注册端(Server)
服务注册端负责将服务信息(比如服务名、IP 地址、端口等)注册到 Zookeeper 上。
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
public class ServiceRegister {
private static final String ZK_ADDRESS = "localhost:2181";
private static final String SERVICE_PATH = "/services/my-service";
private static ZooKeeper zk;
private static CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
// 创建 Zookeeper 客户端
zk = new ZooKeeper(ZK_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected) {
latch.countDown();
}
}
});
latch.await(); // 等待连接建立
// 注册服务
String serviceInfo = "127.0.0.1:8080";
String nodePath = SERVICE_PATH + "/node_1"; // 服务节点路径
// 如果该节点不存在,创建临时节点
Stat stat = zk.exists(SERVICE_PATH, false);
if (stat == null) {
// 如果服务路径不存在,创建服务路径
zk.create(SERVICE_PATH, "Service Registry".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// 创建临时节点,表示服务实例
String createdNode = zk.create(nodePath, serviceInfo.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("Service registered at path: " + createdNode);
zk.close();
}
}
代码说明:
- Zookeeper 客户端:我们通过
ZooKeeper
类创建客户端,连接到 Zookeeper 服务。 - 服务注册:我们在 Zookeeper 中注册服务时,会在
/services/my-service
路径下创建一个临时节点,节点的数据是服务的地址(例如127.0.0.1:8080
)。 - 临时节点:创建的节点是临时节点(
CreateMode.EPHEMERAL
),意味着当 Zookeeper 断开与客户端的连接时,该节点会自动删除。
3.2 服务发现端(Client)
服务发现端通过监听 Zookeeper 上的服务节点来发现可用的服务。
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class ServiceDiscovery {
private static final String ZK_ADDRESS = "localhost:2181";
private static final String SERVICE_PATH = "/services/my-service";
private static ZooKeeper zk;
private static CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
// 创建 Zookeeper 客户端
zk = new ZooKeeper(ZK_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected) {
latch.countDown();
}
}
});
latch.await(); // 等待连接建立
// 监听服务节点的变化
List<String> services = zk.getChildren(SERVICE_PATH, true); // true 表示监听节点变化
System.out.println("Services available: ");
for (String service : services) {
byte[] data = zk.getData(SERVICE_PATH + "/" + service, false, null);
System.out.println("Service: " + service + ", Data: " + new String(data));
}
// 关闭 Zookeeper 客户端
zk.close();
}
}
代码说明:
- Zookeeper 客户端:客户端与 Zookeeper 进行连接。
- 监听服务节点:
getChildren
方法用来获取服务路径下的所有子节点(即注册的服务实例),并设置监听器,实时更新服务状态。 - 获取服务信息:通过
getData
方法获取服务节点的数据(即服务地址)。
4. 运行流程
- 启动 Zookeeper:首先启动 Zookeeper 服务,确保它在本地运行。
- 注册服务:运行
ServiceRegister
类,模拟服务注册过程。它会将服务信息(如127.0.0.1:8080
)注册到 Zookeeper。 - 发现服务:运行
ServiceDiscovery
类,模拟服务发现过程。它会监听 Zookeeper 上的/services/my-service
路径,获取所有注册的服务信息。
5. 总结
在这个例子中,我们展示了如何使用 Zookeeper 来实现服务注册与发现。具体步骤包括:
- 在 Zookeeper 中注册服务,使用临时节点存储服务信息。
- 通过 Zookeeper 的监视机制,动态获取并更新服务列表。
Zookeeper 就像是一个“指挥中心”,它在分布式系统中解决了很多协调和同步的问题。这里是它常见的用途:
-
分布式锁:它能确保多个服务不会同时去做会发生冲突的事情,类似于排队等候,只让一个人执行任务。
-
配置管理:就像是一个配置仓库,所有服务从这里获取配置信息,保证每个服务用的是同样的配置。
-
服务注册与发现:它让各个服务之间互相知道对方的“位置”,比如“我在这里,大家可以来找我”。
-
领导者选举:当需要决定谁来做某个任务时,Zookeeper 负责选举一个“领导”,其他人都得跟着。
-
分布式队列:它帮助多个服务按顺序处理任务,确保任务一个接一个,不会乱跑。
-
通知机制:它能实时通知其他服务,某个数据或配置发生了变化,大家得更新一下。