使用 Zookeeper 实现负载均衡的实用方案
一 核心思路
二 方案一 客户端直连多个 Zookeeper 节点
import org.apache.zookeeper.ZooKeeper;
public class ZkClient {
public static void main(String[] args) throws Exception {
// 多个地址用逗号分隔
String connectString = "zk1:2181,zk2:2181,zk3:2181";
int sessionTimeout = 3000;
ZooKeeper zk = new ZooKeeper(connectString, sessionTimeout, event -> {
// 处理连接/会话事件
});
// ... 使用 zk
}
}
三 方案二 基于 Zookeeper 的服务注册与发现实现负载均衡
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import java.nio.charset.StandardCharsets;
public class ServiceRegistry {
private static final String ROOT = "/services/your-service";
public static void main(String[] args) throws Exception {
String connectString = "zk1:2181,zk2:2181,zk3:2181";
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(connectString)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
client.start();
// 确保根节点
client.create().creatingParentsIfNeeded().forPath(ROOT);
// 注册自己(示例IP与端口)
String instance = "192.168.1.10:8080";
String path = ROOT + "/" + instance;
client.create().withMode(CreateMode.EPHEMERAL).forPath(path, instance.getBytes(StandardCharsets.UTF_8));
// 监听实例列表变化
PathChildrenCache cache = new PathChildrenCache(client, ROOT, true);
cache.start();
cache.getListenable().addListener((c, event) -> {
switch (event.getType()) {
case CHILD_ADDED -> System.out.println("Added: " + new String(event.getData().getData()));
case CHILD_REMOVED -> System.out.println("Removed: " + new String(event.getData().getData()));
case CHILD_UPDATED -> System.out.println("Updated: " + new String(event.getData().getData()));
}
});
// 阻塞等待
Thread.sleep(Long.MAX_VALUE);
}
}
四 方案三 使用 Nginx 或 HAProxy 对 Zookeeper 做四层转发
stream {
upstream zookeeper {
server zk1:2181;
server zk2:2181;
server zk3:2181;
}
server {
listen 2181;
proxy_pass zookeeper;
proxy_timeout 1s;
proxy_responses 1;
}
}
五 实践建议与注意事项