Zookeeper实现负载均衡的核心逻辑与步骤
Zookeeper并非专门的负载均衡工具,但凭借其服务注册与发现、动态数据同步、Watcher事件通知等特性,可作为分布式系统的负载均衡协调中心,帮助客户端实现智能的服务调用负载均衡。以下是具体实现流程:
负载均衡需高可用的Zookeeper集群支撑,步骤如下:
/var/lib/zookeeper)和日志目录(/var/log/zookeeper)。zoo.cfg文件,添加集群配置:tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=node1:2888:3888 # server.X格式:服务器ID:peer通信端口:Leader选举端口
server.2=node2:2888:3888
server.3=node3:2888:3888
dataDir目录下创建myid文件,内容为对应的服务器ID(如node1的myid文件内容为1,node2为2,以此类推)。zkServer.sh start启动Zookeeper服务,通过echo stat | nc node1 2181验证集群状态(需显示Mode: leader或Mode: follower)。服务提供者启动时,需将自己的服务地址、端口、权重等信息注册到Zookeeper,形成服务节点列表。常用节点类型为临时节点(EPHEMERAL)(客户端断开连接后自动删除,确保服务下线及时感知):
// 示例:Java客户端注册服务(服务名:order-service,地址:192.168.1.100:8080)
String serviceName = "/services/order-service";
String servicePath = serviceName + "/192.168.1.100:8080";
zk.create(servicePath, "192.168.1.100:8080".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
注册后,Zookeeper中会生成类似/services/order-service/192.168.1.100:8080的节点,客户端可通过serviceName路径获取所有可用服务提供者。
服务消费者启动时,通过Zookeeper客户端获取serviceName路径下的所有子节点(即服务提供者列表),并监听节点变化(如新增、删除):
// 示例:Java客户端获取服务列表并监听
List<String> providers = zk.getChildren(serviceName, true); // true表示开启监听
for (String provider : providers) {
String address = new String(zk.getData(serviceName + "/" + provider, false, null));
System.out.println("Available provider: " + address);
}
当服务提供者上线(新增节点)或下线(节点删除)时,Zookeeper会通过Watcher机制通知消费者,消费者可实时更新本地服务列表。
消费者从获取的服务列表中,通过负载均衡策略选择一个提供者发起请求。常见策略包括:
weight=2表示处理能力是默认节点的2倍)分配请求,适用于节点性能差异大的场景。示例:轮询策略实现(Java)
public class RoundRobinLoadBalancer {
private List<String> providers;
private AtomicInteger index = new AtomicInteger(0);
public RoundRobinLoadBalancer(List<String> providers) {
this.providers = providers;
}
public String select() {
int size = providers.size();
if (size == 0) throw new RuntimeException("No available providers");
int currentIndex = index.getAndIncrement() % size;
return providers.get(currentIndex);
}
}
消费者通过select()方法获取目标提供者地址,发起请求。
由于Zookeeper的实时同步和Watcher机制,当服务提供者发生变化(如新增、下线、权重调整)时,消费者会立即收到通知,更新本地服务列表并重新选择提供者,无需人工干预。例如:
NodeChildrenChanged事件,获取新列表并更新。NodeDeleted事件,移除该节点并重新选择。