🌺The Begin🌺点点关注,收藏不迷路🌺

在分布式系统中,有一个经典的难题:如何让一群互不信任的服务器达成共识? 谁来做主?如何选主?配置变更怎么通知?这些看似简单的问题,在分布式环境下变得异常复杂。而ZooKeeper,就是为了解决这些问题而生的。

1. 什么是ZooKeeper?

1.1 官方定义

ZooKeeper是一个开源的分布式协调服务,是Hadoop生态系统的核心组件之一。它提供了一组简单的原语,用于实现分布式系统中常见的协调任务,如:

  • 配置管理
  • 命名服务
  • 分布式锁
  • 集群管理
  • 领导者选举

1.2 ZooKeeper在生态系统中的位置

基础架构层

协调服务层

分布式应用层

HBase

Kafka

Dubbo

Spark

ZooKeeper
分布式协调服务

HDFS

1.3 ZooKeeper的设计目标

/**
 * ZooKeeper的核心设计理念
 */
public class ZooKeeperDesign {
    
    // 1. 简单性 - 提供简单的原语操作
    // create(path, data, flags)
    // delete(path, version)
    // exists(path, watch)
    // getData(path, watch)
    // setData(path, data, version)
    // getChildren(path, watch)
    
    // 2. 高可用 - 集群模式,只要多数节点存活就能工作
    // 3. 顺序一致性 - 全局唯一的递增事务ID
    // 4. 高性能 - 读写分离,读性能随节点增加而提升
}

2. ZooKeeper的核心概念

2.1 数据模型:ZNode

ZooKeeper的数据模型是一个层次化的命名空间,类似于文件系统的树形结构:

/ (根节点)

/zookeeper
ZK服务节点

/app1
应用1根节点

/app2
应用2根节点

/config
配置根节点

/zookeeper/quota
ZK配额信息

/app1/master
Master选举

/app1/servers
服务器列表

/app1/servers/server1
Server1信息

/app1/servers/server2
Server2信息

/app2/lock
分布式锁

/config/db
数据库配置

/config/cache
缓存配置

ZNode的类型

ZNode类型特点适用场景
持久节点创建后一直存在,直到显式删除存储配置信息、元数据
临时节点会话结束时自动删除服务注册、心跳检测
顺序节点名称自动附加递增序号分布式锁、队列
容器节点子节点删除后自动删除特定生命周期管理

2.2 节点属性

/**
 * ZNode的元数据结构
 */
public class ZNodeStat {
    private long czxid;           // 创建时的事务ID
    private long mzxid;           // 最后修改时的事务ID
    private long ctime;           // 创建时间
    private long mtime;           // 修改时间
    private int version;          // 数据版本号
    private int cversion;         // 子节点版本号
    private int aversion;         // ACL版本号
    private long ephemeralOwner;  // 临时节点所有者会话ID
    private int dataLength;       // 数据长度
    private int numChildren;      // 子节点数量
    private long pzxid;           // 子节点最后修改事务ID
}

2.3 会话(Session)

/**
 * ZooKeeper会话管理
 */
public class ZKSessionManager {
    
    private long sessionId;        // 会话ID
    private int sessionTimeout;     // 会话超时时间
    private long lastHeartbeat;     // 最后心跳时间
    private SessionState state;     // 会话状态
    
    enum SessionState {
        CONNECTING,    // 连接中
        CONNECTED,     // 已连接
        CLOSED,        // 已关闭
        EXPIRED        // 会话过期
    }
    
    /**
     * 会话保活机制
     */
    public void keepAlive() {
        ScheduledExecutorService scheduler = 
            Executors.newScheduledThreadPool(1);
        
        // 定期发送心跳(超时时间的1/3)
        scheduler.scheduleAtFixedRate(() -> {
            if (state == SessionState.CONNECTED) {
                sendHeartbeat();
                lastHeartbeat = System.currentTimeMillis();
            }
        }, sessionTimeout / 3, sessionTimeout / 3, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 检测会话超时
     */
    public void checkTimeout() {
        long now = System.currentTimeMillis();
        if (now - lastHeartbeat > sessionTimeout) {
            state = SessionState.EXPIRED;
            handleSessionExpired();
        }
    }
}

3. ZooKeeper的核心功能

3.1 配置管理

/**
 * 使用ZooKeeper实现动态配置管理
 */
public class ConfigManager {
    
    private ZooKeeper zk;
    private String configPath = "/config/app";
    private Map<String, String> localCache = new HashMap<>();
    
    public ConfigManager(String connectString) throws Exception {
        this.zk = new ZooKeeper(connectString, 3000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 配置变更时的回调
                if (event.getType() == EventType.NodeDataChanged) {
                    refreshConfig(event.getPath());
                }
            }
        });
    }
    
    /**
     * 发布配置
     */
    public void publishConfig(String key, String value) throws Exception {
        String path = configPath + "/" + key;
        
        // 检查节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null) {
            // 创建配置节点
            zk.create(path, value.getBytes(), 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                CreateMode.PERSISTENT);
        } else {
            // 更新配置
            zk.setData(path, value.getBytes(), stat.getVersion());
        }
    }
    
    /**
     * 获取配置(带本地缓存)
     */
    public String getConfig(String key) throws Exception {
        // 先从本地缓存获取
        if (localCache.containsKey(key)) {
            return localCache.get(key);
        }
        
        // 从ZooKeeper获取
        String path = configPath + "/" + key;
        byte[] data = zk.getData(path, true, null);
        String value = new String(data);
        
        // 更新缓存
        localCache.put(key, value);
        return value;
    }
    
    /**
     * 刷新配置
     */
    private void refreshConfig(String path) {
        try {
            String key = path.substring(path.lastIndexOf("/") + 1);
            byte[] data = zk.getData(path, true, null);
            String value = new String(data);
            
            // 更新本地缓存
            localCache.put(key, value);
            
            System.out.println("配置已更新: " + key + " = " + value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.2 命名服务

/**
 * 使用ZooKeeper实现分布式命名服务
 */
public class NamingService {
    
    private ZooKeeper zk;
    private String rootPath = "/services";
    
    public NamingService(String connectString) throws Exception {
        this.zk = new ZooKeeper(connectString, 3000, null);
        
        // 创建根节点
        ensurePath(rootPath);
    }
    
    /**
     * 服务注册
     */
    public void registerService(String serviceName, String address) throws Exception {
        String servicePath = rootPath + "/" + serviceName;
        ensurePath(servicePath);
        
        // 创建临时顺序节点
        String instancePath = servicePath + "/instance";
        String createdPath = zk.create(instancePath, 
            address.getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL);
        
        System.out.println("服务注册成功: " + createdPath + " -> " + address);
    }
    
    /**
     * 服务发现
     */
    public List<String> discoverService(String serviceName) throws Exception {
        String servicePath = rootPath + "/" + serviceName;
        
        // 获取所有服务实例
        List<String> instances = zk.getChildren(servicePath, true);
        List<String> addresses = new ArrayList<>();
        
        for (String instance : instances) {
            String instancePath = servicePath + "/" + instance;
            byte[] data = zk.getData(instancePath, false, null);
            addresses.add(new String(data));
        }
        
        return addresses;
    }
    
    /**
     * 监控服务变更
     */
    public void watchService(String serviceName) throws Exception {
        String servicePath = rootPath + "/" + serviceName;
        
        zk.getChildren(servicePath, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                if (event.getType() == EventType.NodeChildrenChanged) {
                    System.out.println("服务列表发生变化");
                    try {
                        // 重新获取并监控
                        watchService(serviceName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
    
    private void ensurePath(String path) throws Exception {
        if (zk.exists(path, false) == null) {
            zk.create(path, new byte[0], 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                CreateMode.PERSISTENT);
        }
    }
}

3.3 分布式锁

/**
 * 基于ZooKeeper实现分布式锁
 */
public class DistributedLock {
    
    private ZooKeeper zk;
    private String lockPath = "/locks/myLock";
    private String currentLockPath;
    private CountDownLatch lockAcquiredSignal = new CountDownLatch(1);
    
    public DistributedLock(String connectString) throws Exception {
        this.zk = new ZooKeeper(connectString, 3000, null);
    }
    
    /**
     * 获取锁
     */
    public void lock() throws Exception {
        // 创建临时顺序节点
        currentLockPath = zk.create(lockPath + "/lock-", 
            new byte[0],
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL);
        
        // 尝试获取锁
        tryLock();
        
        // 等待获取锁
        lockAcquiredSignal.await();
    }
    
    private void tryLock() throws Exception {
        // 获取所有子节点
        List<String> children = zk.getChildren(lockPath, false);
        
        // 按序号排序
        Collections.sort(children);
        
        // 当前节点名称
        String currentNode = currentLockPath.substring(
            currentLockPath.lastIndexOf("/") + 1);
        
        // 检查是否是最小节点
        int currentIndex = children.indexOf(currentNode);
        if (currentIndex == 0) {
            // 获取到锁
            lockAcquiredSignal.countDown();
        } else {
            // 监听前一个节点
            String previousNode = children.get(currentIndex - 1);
            String previousPath = lockPath + "/" + previousNode;
            
            zk.exists(previousPath, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getType() == EventType.NodeDeleted) {
                        try {
                            // 前一个节点释放了锁,重新尝试获取
                            tryLock();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }
    
    /**
     * 释放锁
     */
    public void unlock() throws Exception {
        if (currentLockPath != null) {
            zk.delete(currentLockPath, -1);
            currentLockPath = null;
        }
    }
    
    /**
     * 使用示例
     */
    public static void main(String[] args) {
        DistributedLock lock = new DistributedLock("localhost:2181");
        
        try {
            // 获取锁
            lock.lock();
            
            // 执行临界区代码
            System.out.println("获取到锁,执行任务...");
            Thread.sleep(5000);
            
            // 释放锁
            lock.unlock();
            System.out.println("释放锁");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.4 集群管理与领导者选举

/**
 * 使用ZooKeeper实现集群管理和领导者选举
 */
public class ClusterManager {
    
    private ZooKeeper zk;
    private String electionPath = "/election";
    private String clusterPath = "/cluster";
    private String nodeId;
    private boolean isLeader = false;
    
    public ClusterManager(String connectString, String nodeId) throws Exception {
        this.nodeId = nodeId;
        this.zk = new ZooKeeper(connectString, 3000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 处理集群事件
                handleClusterEvent(event);
            }
        });
        
        // 初始化路径
        ensurePath(electionPath);
        ensurePath(clusterPath);
    }
    
    /**
     * 启动节点并参与选举
     */
    public void start() throws Exception {
        // 在选举路径下创建临时顺序节点
        String participantPath = electionPath + "/participant-";
        String createdPath = zk.create(participantPath, 
            nodeId.getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL);
        
        System.out.println("节点 " + nodeId + " 加入选举: " + createdPath);
        
        // 触发选举
        electLeader();
    }
    
    /**
     * 领导者选举
     */
    private void electLeader() throws Exception {
        List<String> participants = zk.getChildren(electionPath, false);
        
        if (participants.isEmpty()) {
            return;
        }
        
        // 按序号排序
        Collections.sort(participants);
        
        // 序号最小的节点成为领导者
        String leaderNode = participants.get(0);
        String leaderPath = electionPath + "/" + leaderNode;
        byte[] data = zk.getData(leaderPath, false, null);
        String leaderId = new String(data);
        
        // 判断自己是否是领导者
        if (leaderId.equals(nodeId)) {
            isLeader = true;
            becomeLeader();
        } else {
            isLeader = false;
            becomeFollower(leaderId);
        }
        
        // 广播集群状态
        updateClusterState();
    }
    
    /**
     * 成为领导者
     */
    private void becomeLeader() {
        System.out.println("节点 " + nodeId + " 成为领导者");
        
        // 启动领导者任务
        startLeaderTasks();
    }
    
    /**
     * 成为追随者
     */
    private void becomeFollower(String leaderId) {
        System.out.println("节点 " + nodeId + " 成为追随者,领导者: " + leaderId);
        
        // 监控领导者
        watchLeader();
    }
    
    /**
     * 监控领导者状态
     */
    private void watchLeader() {
        try {
            List<String> participants = zk.getChildren(electionPath, true);
            
            if (!participants.isEmpty()) {
                String leaderNode = participants.get(0);
                String leaderPath = electionPath + "/" + leaderNode;
                
                // 监控领导者节点
                zk.exists(leaderPath, true);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 处理集群事件
     */
    private void handleClusterEvent(WatchedEvent event) {
        System.out.println("集群事件: " + event.getType());
        
        if (event.getType() == EventType.NodeChildrenChanged) {
            // 参与者列表变化,重新选举
            try {
                electLeader();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (event.getType() == EventType.NodeDeleted) {
            // 节点退出,检查是否需要重新选举
            try {
                electLeader();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 更新集群状态
     */
    private void updateClusterState() throws Exception {
        String statePath = clusterPath + "/state";
        String state = "Leader: " + (isLeader ? nodeId : "none") + 
                      ", Current node: " + nodeId;
        
        Stat stat = zk.exists(statePath, false);
        if (stat == null) {
            zk.create(statePath, state.getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL);
        } else {
            zk.setData(statePath, state.getBytes(), stat.getVersion());
        }
    }
    
    private void ensurePath(String path) throws Exception {
        if (zk.exists(path, false) == null) {
            zk.create(path, new byte[0],
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.PERSISTENT);
        }
    }
    
    private void startLeaderTasks() {
        // 领导者才执行的任务
        // 如:调度作业、负载均衡等
    }
}

4. ZooKeeper的架构与原理

4.1 集群架构

ZooKeeper Ensemble

Leader

Follower

Follower

Observer

客户端

客户端

客户端

客户端

4.2 Zab协议:ZooKeeper的原子广播协议

/**
 * Zab协议的核心机制
 */
public class ZabProtocol {
    
    /**
     * 三个阶段的事务提交
     */
    class Transaction {
        long zxid;           // 事务ID(epoch + counter)
        byte[] data;         // 事务数据
        List<Follower> ack;  // 确认的follower
        
        // 阶段1: Leader提议
        void propose() {
            // Leader生成提议并广播
            broadcastProposal();
        }
        
        // 阶段2: Follower确认
        void ack(Follower follower) {
            ack.add(follower);
            
            // 收到多数派确认
            if (ack.size() > (ensembleSize / 2)) {
                commit();
            }
        }
        
        // 阶段3: Leader提交
        void commit() {
            // 广播提交消息
            broadcastCommit();
            applyToStateMachine();
        }
    }
    
    /**
     * 崩溃恢复:Leader选举
     */
    class LeaderElection {
        
        long getHighestZxid() {
            // 获取集群中最高的zxid
            // 拥有最高zxid的节点最有资格成为Leader
        }
        
        boolean isMajority(List<Vote> votes) {
            // 判断是否获得多数派支持
            return votes.size() > (ensembleSize / 2);
        }
    }
}

4.3 读写一致性保证

/**
 * ZooKeeper的一致性保证
 */
public class ConsistencyGuarantees {
    
    /**
     * 顺序一致性(Sequential Consistency)
     */
    public void sequentialConsistency() {
        // 所有事务按照zxid顺序执行
        // 客户端看到的数据变更顺序与Leader提交顺序一致
    }
    
    /**
     * 原子性(Atomicity)
     */
    public void atomicity() {
        // 事务要么完全成功,要么完全失败
        // 不存在部分成功的情况
    }
    
    /**
     * 单一系统镜像(Single System Image)
     */
    public void singleSystemImage() {
        // 客户端无论连接到哪个服务器,看到的是同一份数据视图
        // 通过同步操作sync()确保读取最新数据
    }
    
    /**
     * 持久性(Durability)
     */
    public void durability() {
        // 事务一旦提交,数据持久化
        // 即使Leader宕机,新Leader也有已提交的事务
    }
    
    /**
     * 实时性(Timeliness)
     */
    public void timeliness() {
        // 保证在一定时间内系统收敛到一致状态
        // 通过会话超时机制实现
    }
}

5. 实战:ZooKeeper典型应用场景

5.1 HBase元数据管理

/**
 * HBase使用ZooKeeper管理RegionServer和元数据
 */
public class HBaseZooKeeperIntegration {
    
    /**
     * HBase在ZooKeeper中的节点结构
     */
    class HBaseZNodes {
        // /hbase/master                - 主HMaster节点
        // /hbase/backup-masters         - 备份HMaster
        // /hbase/rs                     - 在线RegionServer列表
        // /hbase/table                  - 表元数据
        // /hbase/table-lock              - 表锁
        // /hbase/region-in-transition    - 正在移动的Region
        // /hbase/splitlog                - Region分裂日志
    }
    
    /**
     * 监控RegionServer状态
     */
    public void watchRegionServers(ZooKeeper zk) throws Exception {
        String rsPath = "/hbase/rs";
        
        zk.getChildren(rsPath, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                if (event.getType() == EventType.NodeChildrenChanged) {
                    System.out.println("RegionServer列表变化");
                    // 重新分配Region
                    reassignRegions();
                }
            }
        });
    }
}

5.2 Kafka集群管理

/**
 * Kafka使用ZooKeeper管理Broker和Topic
 */
public class KafkaZooKeeperIntegration {
    
    /**
     * Kafka在ZooKeeper中的节点结构
     */
    class KafkaZNodes {
        // /brokers/ids                 - Broker列表
        // /brokers/topics               - Topic元数据
        // /controller                   - Controller节点
        // /admin                        - 管理操作
        // /consumers                     - 消费者组
        // /config                        - 配置信息
    }
    
    /**
     * Broker注册与发现
     */
    public void registerBroker(ZooKeeper zk, int brokerId, String host, int port) 
            throws Exception {
        String brokerPath = "/brokers/ids/" + brokerId;
        String brokerInfo = String.format(
            "{\"host\":\"%s\",\"port\":%d}", host, port);
        
        // 创建临时节点
        zk.create(brokerPath, brokerInfo.getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL);
    }
}

5.3 Dubbo服务治理

/**
 * Dubbo使用ZooKeeper实现服务注册与发现
 */
public class DubboZooKeeperIntegration {
    
    /**
     * Dubbo在ZooKeeper中的节点结构
     */
    class DubboZNodes {
        // /dubbo                       - 根节点
        //   /com.example.UserService     - 服务接口
        //     /providers                 - 服务提供者
        //       /dubbo://192.168.1.1:20880 - 提供者URL
        //     /consumers                 - 服务消费者
        //       /consumer://192.168.1.2    - 消费者URL
        //     /configurators             - 动态配置
        //     /routers                    - 路由规则
    }
    
    /**
     * 服务提供者注册
     */
    public void registerProvider(ZooKeeper zk, String service, String url) 
            throws Exception {
        String providerPath = String.format(
            "/dubbo/%s/providers/%s", service, encode(url));
        
        zk.create(providerPath, new byte[0],
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL);
    }
    
    private String encode(String url) {
        // URL编码,因为ZNode名称不能包含特殊字符
        return URLEncoder.encode(url);
    }
}

6. 监控与运维

6.1 常用四字命令

# 查看ZooKeeper状态
echo stat | nc localhost 2181

# 查看ZooKeeper配置
echo conf | nc localhost 2181

# 查看客户端连接
echo cons | nc localhost 2181

# 查看节点列表
echo ls / | nc localhost 2181

# 查看监控信息
echo mntr | nc localhost 2181

# 查看是否健康
echo ruok | nc localhost 2181  # 返回"imok"表示健康

6.2 Java监控API

/**
 * ZooKeeper监控工具
 */
public class ZKMonitor {
    
    private ZooKeeper zk;
    private String connectString;
    
    public void monitor() throws Exception {
        // 获取ZooKeeper状态
        ZooKeeper.States state = zk.getState();
        System.out.println("连接状态: " + state);
        
        // 获取会话ID
        long sessionId = zk.getSessionId();
        System.out.println("会话ID: " + sessionId);
        
        // 获取会话超时时间
        int sessionTimeout = zk.getSessionTimeout();
        System.out.println("会话超时: " + sessionTimeout + "ms");
        
        // 检查根节点
        Stat rootStat = zk.exists("/", false);
        System.out.println("根节点数据版本: " + rootStat.getVersion());
        System.out.println("子节点数量: " + rootStat.getNumChildren());
    }
    
    /**
     * 性能指标收集
     */
    public void collectMetrics() throws Exception {
        // 连接到ZooKeeper管理端口
        Socket socket = new Socket("localhost", 2181);
        PrintWriter out = new PrintWriter(socket.getOutputStream());
        BufferedReader in = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        
        // 发送mntr命令
        out.println("mntr");
        out.flush();
        
        // 解析指标
        String line;
        while ((line = in.readLine()) != null) {
            String[] parts = line.split("\t");
            if (parts.length == 2) {
                String metric = parts[0];
                String value = parts[1];
                
                switch (metric) {
                    case "zk_znode_count":
                        System.out.println("ZNode数量: " + value);
                        break;
                    case "zk_watch_count":
                        System.out.println("Watcher数量: " + value);
                        break;
                    case "zk_approximate_data_size":
                        System.out.println("数据大小: " + value + " bytes");
                        break;
                    case "zk_open_file_descriptor_count":
                        System.out.println("打开文件数: " + value);
                        break;
                    case "zk_packets_received":
                        System.out.println("接收包数: " + value);
                        break;
                }
            }
        }
    }
}

6.3 常见问题排查

问题症状可能原因解决方案
连接超时客户端无法连接网络问题、服务器负载高检查网络,增加超时时间
会话过期Session expired错误客户端长时间未心跳增加会话超时,优化GC
Leader选举慢服务长时间不可用网络分区、磁盘慢检查网络,优化磁盘IO
数据不一致读取到旧数据未使用sync操作读关键数据前调用sync
Watcher堆积性能下降过多Watcher未移除及时移除不需要的Watcher

7. 总结

7.1 ZooKeeper的核心价值

ZooKeeper

一致性
所有服务器数据一致

可靠性
多数节点存活即可用

顺序性
全局事务ID保证顺序

实时性
变更立即通知客户端

简单性
简单的文件系统API

7.2 ZooKeeper的应用场景总结

场景实现方式典型应用
配置管理持久节点 + WatcherHBase、Kafka配置
命名服务顺序节点Dubbo服务发现
分布式锁临时顺序节点分布式任务调度
集群管理临时节点 + WatcherHBase RegionServer监控
领导者选举临时顺序节点 + WatcherKafka Controller选举
队列管理顺序节点分布式任务队列

7.3 最佳实践

  1. 会话超时设置:一般为2-5倍的心跳间隔
  2. ZNode大小控制:数据不要超过1MB
  3. Watcher使用:用完即删,避免内存泄漏
  4. 集群规模:奇数台服务器(3、5、7)
  5. 读写分离:使用Observer扩展读能力

7.4 核心口诀

  1. 数据模型:树形结构,类似文件系统
  2. 节点类型:持久、临时、顺序、容器
  3. 核心功能:配置、命名、锁、选举
  4. 集群架构:Leader、Follower、Observer
  5. 一致性:Zab协议,多数派提交

ZooKeeper作为分布式系统的基石,以其简单而强大的原语,解决了分布式协调中的各种难题。深入理解ZooKeeper,对于构建可靠的分布式系统至关重要。希望本文能帮助你在实际项目中更好地使用ZooKeeper!

#ZooKeeper #分布式系统 #协调服务 #Hadoop #大数据

在这里插入图片描述


🌺The End🌺点点关注,收藏不迷路🌺
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐