Zookeeper是如何保证创建的节点是唯一的?

典型回答 Zookeeper通过两个手段来保证节点创建的唯一性: 1、所有的写请求都会由Leader进行,即使是请求到Follower节点,也会被转发到Leader节点上执行。 2、在Leader上写入数据的时候,通过加锁(synchronized)和CAS(ConcurrentHashMap)操作,保证了并发情况下只有一个线程可以添加成功。 第一点我们就不展开讲了,这个是ZK中的角色天然具备的特性,我们重点展开说说第二点原因。我们来看下ZK的源码,看看到底是如何创建节点的。 以下代码在github中可以看到,在DataTree的createNode方法就是进行节点创建的: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public void createNode(final String path, byte[] data, List<ACL> acl, long ephemeralOwner, int parentCVersion, long zxid, long time, Stat outputStat) throws NoNodeException, NodeExistsException { int lastSlash = path.lastIndexOf('/'); String parentName = path.substring(0, lastSlash); String childName = path.substring(lastSlash + 1); StatPersisted stat = createStat(zxid, time, ephemeralOwner); DataNode parent = nodes.get(parentName); if (parent == null) { throw new NoNodeException(); } synchronized (parent) { // Add the ACL to ACL cache first, to avoid the ACL not being // created race condition during fuzzy snapshot sync. // // This is the simplest fix, which may add ACL reference count // again if it's already counted in the ACL map of fuzzy // snapshot, which might also happen for deleteNode txn, but // at least it won't cause the ACL not exist issue. // // Later we can audit and delete all non-referenced ACLs from // ACL map when loading the snapshot/txns from disk, like what // we did for the global sessions. Long acls = aclCache.convertAcls(acl); Set<String> children = parent.getChildren(); if (children.contains(childName)) { throw new NodeExistsException(); } nodes.preChange(parentName, parent); if (parentCVersion == -1) { parentCVersion = parent.stat.getCversion(); parentCVersion++; } // There is possibility that we'll replay txns for a node which // was created and then deleted in the fuzzy range, and it's not // exist in the snapshot, so replay the creation might revert the // cversion and pzxid, need to check and only update when it's // larger. if (parentCVersion > parent.stat.getCversion()) { parent.stat.setCversion(parentCVersion); parent.stat.setPzxid(zxid); } DataNode child = new DataNode(data, acls, stat); parent.addChild(childName); nodes.postChange(parentName, parent); nodeDataSize.addAndGet(getNodeSize(path, child.data)); nodes.put(path, child); EphemeralType ephemeralType = EphemeralType.get(ephemeralOwner); if (ephemeralType == EphemeralType.CONTAINER) { containers.add(path); } else if (ephemeralType == EphemeralType.TTL) { ttls.add(path); } else if (ephemeralOwner != 0) { HashSet<String> list = ephemerals.computeIfAbsent(ephemeralOwner, k -> new HashSet<>()); synchronized (list) { list.add(path); } } if (outputStat != null) { child.copyStat(outputStat); } } // now check if its one of the zookeeper node child if (parentName.startsWith(quotaZookeeper)) { // now check if it's the limit node if (Quotas.limitNode.equals(childName)) { // this is the limit node // get the parent and add it to the trie pTrie.addPath(Quotas.trimQuotaPath(parentName)); } if (Quotas.statNode.equals(childName)) { updateQuotaForPath(Quotas.trimQuotaPath(parentName)); } } String lastPrefix = getMaxPrefixWithQuota(path); long bytes = data == null ? 0 : data.length; // also check to update the quotas for this node if (lastPrefix != null) { // ok we have some match and need to update updateQuotaStat(lastPrefix, bytes, 1); } updateWriteStat(path, bytes); dataWatches.triggerWatch(path, Event.EventType.NodeCreated, zxid); childWatches.triggerWatch(parentName.equals("") ? "/" : parentName, Event.EventType.NodeChildrenChanged, zxid); } 以上代码中,第10 行,针对当前要创建的节点的父节点添加了互斥锁,主要是用来避免并发,这样就可以在同一时刻,只有一个线程可以在父节点下写内容。 ...

March 22, 2026 · 4 min · santu

Zookeeper的缺点有哪些?

典型回答 ZooKeeper 是一个分布式协调组件,在分布式系统中被广泛应用,但是其实他还是存在很多缺点的。 最重要的就是性能问题,ZooKeeper 设计是为了高一致性,其 ZAB 协议需要同步写操作到大多数节点,导致写操作的性能较低。在高并发写入场景下,ZooKeeper 的性能会成为瓶颈。 但是知道CAP的大家都知道,一致性和可用性之间,只能选择一个,ZK选了一致性,那就势必会牺牲一定的可用性,而性能就是可用性中非常关键的一个指标。 ✅Zookeeper是CP的还是AP的? 第二个就是ZooKeeper 的所有写操作必须经过 Leader 节点处理,所有写请求都需要通过 Leader 同步到其他节点。那么这个Leader就是整个集群的瓶颈,如果 Leader 负载过高,就可能会导致性能下降。如果Leader挂了,就会无法工作(直到新的leader选举成功) 第三,ZooKeeper 将数据存储在内存中,以提供快速访问性能。这意味着它不适合存储大量数据,通常只适合存储小型的元数据和配置信息。如果数据量过大,会导致内存不足或性能下降。 还有就是,ZooKeeper 假设节点之间的网络和节点状态变化是少见的。如果网络分区或节点频繁故障,会频繁触发 Leader 选举,影响可用性。 相较于一些现代分布式协调工具(如 etcd、Consul),ZooKeeper 的易用性和工具生态略显不足,运维和管理复杂度较高。

March 22, 2026 · 1 min · santu

留言给博主