Skip to content

ZooKeeper

简介

Apache ZooKeeper 是分布式协调服务,用于维护配置信息、命名服务、分布式同步和组服务。它是许多分布式系统的核心组件。

数据模型

ZooKeeper 的数据模型是层次化的命名空间,类似文件系统:

/
├── /dubbo
│   ├── /com.example.UserService
│   │   ├── /providers
│   │   │   ├── /dubbo://192.168.1.1:20880
│   │   │   └── /dubbo://192.168.1.2:20880
│   │   └── /consumers
│   └── /configurators
├── /config
│   ├── /database.url
│   └── /redis.host
└── /lock

节点类型

  • 持久节点:创建后一直存在,除非主动删除
  • 临时节点:创建它的会话结束后自动删除
  • 顺序节点:创建时自动在名称后追加递增序号

核心功能

服务发现(与 Dubbo 集成)

java
// 服务提供者注册
ZooKeeper zk = new ZooKeeper("localhost:2181", 3000, null);
String path = "/dubbo/service/providers/dubbo://192.168.1.1:20880";
zk.create(path, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

// 服务消费者监听
zk.getChildren("/dubbo/service/providers", event -> {
    // 服务列表变化时重新获取
    List<String> providers = zk.getChildren("/dubbo/service/providers", false);
});

分布式锁

java
public class DistributedLock {
    private ZooKeeper zk;
    private String lockPath = "/locks/lock";

    public void lock() throws Exception {
        String node = zk.create(lockPath, null, 
            ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        // 获取所有子节点并排序,检查自己是否是最小节点
        List<String> children = zk.getChildren("/locks", false);
        Collections.sort(children);
        String currentNode = node.substring(node.lastIndexOf("/") + 1);
        if (!currentNode.equals(children.get(0))) {
            // 监听前一个节点
            String prevNode = children.get(children.indexOf(currentNode) - 1);
            CountDownLatch latch = new CountDownLatch(1);
            zk.exists("/locks/" + prevNode, event -> latch.countDown());
            latch.await();
        }
    }

    public void unlock() throws Exception {
        zk.delete(lockPath, -1);
    }
}

集群角色

角色职责
Leader处理写请求,协调集群
Follower处理读请求,参与选举
Observer处理读请求,不参与选举

ZAB 协议:ZooKeeper 使用 ZAB(ZooKeeper Atomic Broadcast)协议保证数据一致性。