Zookeeper笔记
2026/3/18 0:13:33 网站建设 项目流程

一 : zookeeper介绍

概念: zookeeper他是一个分布式协调组件

使用场景1:分布式协调组件

使用场景2:分布式锁

​ zk在实现分布式锁上,可以做到强一致性,关于分布式锁的相关知识,会在之后的ZAB协议中介绍

使用场景3:无状态化的实现

二 : zookeeper内部数据模型

1.0 z-node结点——数据类型

# 1.0 启动zookeeper[root@aliyun ~]# /usr/local/zookeeper/bin/zkServer.sh start# 2.0 进入zkcli/usr/local/zookeeper/bin/zkCli.sh# 3.0 创建结点[zk: localhost:2181(CONNECTED)0]ls/[zookeeper][zk: localhost:2181(CONNECTED)1]create /text1 Created /text1[zk: localhost:2181(CONNECTED)2]ls/[text1, zookeeper][zk: localhost:2181(CONNECTED)3]# 4.0 Zookeeper的数据模型是什么样子呢?类似于数据结构中的树,同时也很像文件系统的目录# 5.0 树是由节点所组成,Zookeeper的数据存储也同样是基于节点,这种节点叫做Znode,但是不同于树的节点,Znode的引用方式是路劲引用,类似于文件路径:

2.0 znode节点——组成部分

zk中的node包含四个部分:

组件说明
data节点存储的数据
stat节点元数据(版本号、时间、zxid 等)
ACL权限控制
children子节点列表
[zk: localhost:2181(CONNECTED)3]create /text2 abc Created /text2[zk: localhost:2181(CONNECTED)4]get /text2 abc[zk: localhost:2181(CONNECTED)5]

3.0 znode节点——持久节点和持久序号节点

节点类型是否自动删除是否自动编号典型用途
持久节点❌ 不删除❌ 不编号配置、注册中心目录
持久序号节点❌ 不删除✔ 自动编号排队、分布式锁、唯一序号
# 1.0 创建持久节点[zk: localhost:2181(CONNECTED)5]create /text3 Created /text3# 2.0 创建持久序号节点[zk: localhost:2181(CONNECTED)6]create -s /text4 Created /text40000000003[zk: localhost:2181(CONNECTED)7]

4.0 znode节点——临时节点实现原理以及应用场景

临时节点:临时节点是在会话结束后,自动被删除的,通过这个特性,zk可以实现服务注册与发现的效果

临时序号节点: 类比于持久序号节点

# 1.0 创建临时节点[zk: localhost:2181(CONNECTED)7]create -e /text5 bb Created /text5# 2.0 创建临时序号节点[zk: localhost:2181(CONNECTED)8]create -e -s /text6 cc Created /text60000000005[zk: localhost:2181(CONNECTED)9]

5.0 znode节点——其他类型

# 1.0 container节点: 当容器中无任何子节点时候, 该容器会被zk定期删除[zk: localhost:2181(CONNECTED)9]create -c /mycontainer# 这个容器中没有子节点,会被定期删除Created /mycontainer[zk: localhost:2181(CONNECTED)10]# 2.0 TTL节点:可以指定节点的到期时间,到期后被zk定时删除。只能通过系统配置zookeeper.extendedTypeEnablee=true开启

6.0 zk持久化——数据持久化方案

zk中的数据是运行在内存当中的,zk提供了两种持久化机制

# 1.0 第一种: 事务日志 ,一般放在以下下面[root@aliyun ~]# cd /usr/local/zookeeper/data[root@aliyun data]# lltotal0[root@aliyun data]## 2.0 数据快照# 3.0 原因恢复时,我们先恢复快照文件到内存中; 然后再用日志文件中的数据进行增量备份; 这两种结合,恢复的速度更快。

三 : zookeeper客户端zkcli的使用

1.0 创建和查询节点

# 1.0 创建持久节点/持久序列节点[zk: localhost:2181(CONNECTED)2]create /text7 Created /text7[zk: localhost:2181(CONNECTED)3]create -s /text7 Created /text70000000008# 2.0 创建临时节点/临时序列节点[zk: localhost:2181(CONNECTED)5]create -e /text9 Created /text9[zk: localhost:2181(CONNECTED)6]create -e -s /text9.1 Created /text9.10000000010[zk: localhost:2181(CONNECTED)7]# 3.0 查询[zk: localhost:2181(CONNECTED)7]ls/text7[][zk: localhost:2181(CONNECTED)8]# 4.0 递归查询[zk: localhost:2181(CONNECTED)8]ls-R /text7 /text7[zk: localhost:2181(CONNECTED)9]# 5.0 获取节点的数据[zk: localhost:2181(CONNECTED)10]get /text7 null[zk: localhost:2181(CONNECTED)11]# 6.0 获取详细信息[zk: localhost:2181(CONNECTED)9]get -s /text7 null cZxid=0xd ctime=Mon Nov1715:54:00 CST2025mZxid=0xd mtime=Mon Nov1715:54:00 CST2025pZxid=0xd cversion=0dataVersion=0aclVersion=0ephemeralOwner=0x0 dataLength=0numChildren=0[zk: localhost:2181(CONNECTED)10]

2.0 乐观锁的删除

乐观锁的定义:他是一种并发控制机制。 多个客户端并发修改同一个节点,不会经常冲突。

核心: ZooKeeper 的每次更新操作都必须带上版本号,如果版本号不一致,则更新失败,从而实现乐观锁

[zk: localhost:2181(CONNECTED)37]create /text1 Created /text1[zk: localhost:2181(CONNECTED)38]delete -v1 /text1 version No is not valid:/text1[zk: localhost:2181(CONNECTED)39]delete -v0 /text1[zk: localhost:2181(CONNECTED)40]

3.0 权限设置

acl权限定义了:哪个用户可以操作,怎样操作

# 1.0 zk窗口1# 添加权限addauth digest xiaoming:123456# 创建节点并给予权限create /text-node abc auth:xiaoming:123456:cdrwa# 拿数据get /text-node# 2.0 zk窗口2# 拿数据: 这里我们可以发现是失败的get /text-node# 增加权限addauth digest xiaoming:123456# 拿数据:此时我们发现成功get /text-node

四 : zk实现分布式锁(难)

1.0 读锁和写锁的概念

读锁: 任何人都可以读锁(前提是:没有得到写锁)

写锁: 只要得到写锁的才能写(前提是没有任何锁)

类比:

读锁: 约会

写锁: 结婚

2.0 如何上读锁

✅ 一、ZK 中加读锁的核心思想

读锁 =允许多个读同时存在,但不能与写锁同时存在。

ZK 本身没有“读锁”命令,你需要通过临时顺序节点+节点命名规则实现。

✅ 二、步骤(记住这个流程就能在面试上说出来)

1)创建临时顺序节点

一般路径:

/lock/read-0000001 /lock/read-0000002 /lock/write-0000001

你要“上读锁”,就创建:

/lock/read-xxxxxx (临时顺序节点)

2)判断是否可以获得读锁(最关键)

你创建了一个读锁节点,比如:

/lock/read-0000008

然后你查看比你小的所有节点

getChildren /lock

你要检查:

是否有 “比你小的写锁” 节点存在?

  • 如果没有比你序号更小的 write-xxxx 节点
    → 你可以直接获得读锁
  • 如果有比你小的写锁节点
    → 你不能获得读锁,需要等待

3)监听前一个写锁节点

如果你不能立即上读锁:

  • 找到比你小的最近的写锁节点(序号最接近)
  • watch
    当它删除(写锁释放) → 你再重新判断
    → 直到获取锁

📌 三、举例帮助你理解(面试讲这个非常加分)

当前 /lock 下有:

write-0000001 read-0000002 write-0000003

你创建了:

read-0000004

你看“比你序号小的节点”:

  • write-0000001 ✔(阻塞)
  • read-0000002(不影响读锁)
  • write-0000003 ✔(阻塞)

因为存在比你序号小的写锁节点 →不能获得读锁
你要监听最接近你的写锁:

watch write-0000003
它删除后你再判断是否可以继续获取。

🧠 四、面试 30 秒回答版本

ZK 中读锁是基于临时顺序节点实现的。
读写锁节点统一放在一个目录下,比如 /lock。
上读锁时,客户端创建一个 read- 前缀的临时顺序节点。
然后检查所有比自己小的节点,如果没有 write- 的节点存在,就获得读锁;
如果存在比自己小的 write 节点,就 watch 那个最近的写锁节点,等它删除后再尝试。
所以读锁可以共享,但必须等所有更早的写锁释放后才能获取。

3.0 如何上写锁

✅ 一、ZK 中如何上写锁(Write Lock)

写锁 =独占锁,必须保证前面没有任何节点(无论读、写)。

写锁流程和读锁很像,只是判断条件更严格。

🔒 二、写锁获取流程(记住这 3 步就够了)

1)创建临时顺序节点

路径一般是:

/lock/write-0000001

步骤:

create -e -s /lock/write-

2)检查自己是不是当前序号最小的节点

列出所有节点:

ls/lock

假设你创建的是:

write-0000008

你检查所有节点中比你序号小的节点是否存在?

  • 如果没有比你小的节点 → 你获得写锁
  • 如果有 → 你阻塞等待(不能获取写锁)

⚠️ 注意:
这里不区分 read/write,只要有人比你早排队,你就不能上写锁。

写锁必须严格排队,确保独占。

3)监听“比你小的最近的节点”

如果你的写锁不是最小节点,比如:

read-0000005 write-0000003 read-0000007 write-0000008(你的)

你要监听:

  • 不是所有比你小的节点
  • 而是距离你最近的那个节点read-0000007

当那个节点删除后,你重新判断。

🌟 面试回答:如何在 ZK 中上写锁?

写锁基于临时顺序节点实现。客户端创建 write- 前缀的临时顺序节点,然后列出所有子节点。只要存在比自己序号小的任何节点(包括读节点和写节点),写锁就不能获得。客户端会 watch 那个最接近自己的前一个节点,等它删除后再次判断。最小节点即可获得写锁。

4.0 羊群效应

这个是 ZK 面试必考点!

1.0 什么是羊群效应?

本质:
大量客户端同时 watch 同一个节点,一旦该节点删除,所有客户端同时被唤醒 → 瞬间并发压力巨大。

像一群羊挤着门口,只要门开一点,全冲出去。

2.0 在 ZK 锁场景中可能出现:

如果所有客户端都 watch/lock或某个相同的节点,那么一释放锁,全都被唤醒 → 群体抖动。

🌟 3.0 ZK 如何避免羊群效应?

ZK 官方推荐方案:
每个节点只 watch 排在自己前面的那个节点。

优点:

  • 只唤醒一个客户端
  • 事件传播像链式传递
  • 不会所有客户端一起被唤醒

例如节点:

1, 2, 3, 4, 5

每个节点 watch 自己前一个:

  • 2 watch 1
  • 3 watch 2
  • 4 watch 3
  • 5 watch 4

当 1 删除时:

  • 只唤醒 2
  • 2 获得锁后删除
  • 删除触发 3
  • 依次类推

完全避免羊群效应。

4.0 ⭐ 面试回答:什么是羊群效应?如何避免?

羊群效应就是大量客户端同时监听同一个节点,一旦这个节点变化就导致所有客户端被唤醒,增加服务器压力。
ZooKeeper 通过“只监听自己前一个节点”的方式避免羊群效应,使事件从前往后逐个传递,而不是全部客户端一起触发。

五 : zk的watch机制

1.0 原理介绍

客户端(zkcli,Curator)有一个功能:监听节点的变化

# 1.0 客户端1创建一个节点。并设置监听节点值的变化[zk: localhost:2181(CONNECTED)8]create /text8 Created /text8[zk: localhost:2181(CONNECTED)9]get -w /text8 null[zk: localhost:2181(CONNECTED)10]# 2.0 客户端2设置节点的值[zk: localhost:2181(CONNECTED)2]set/text8 bbb# 3.0 我们在客户端1中取这个值[zk: localhost:2181(CONNECTED)10]WATCHER:: WatchedEvent state:SyncConnected type:NodeDataChanged path:/text8 get /text8 bbb# 4.0 我们在客户端2中任然进行修改[zk: localhost:2181(CONNECTED)3]set/text8 ccc# 5.0 此时我们发现触发不了watch机制了,因为监听他是一次的。 如果想要改变这个情况,我们把第三步改以下,换成以下的情况get -w /text8

2.0 zkcli实现watch

create /text xxxx# 创建节点get -w /text# 一次性监听节点ls-w /text# 监听目录ls-R -w /text# 监听目录中子节点的变化

六 : zookeeper集群

1.0 节点的角色

leader: 主节点

Follower:从节点

Observer:观察者

2.0 集群搭建及连接

1.0 创建myid 文件

其中有一个节点是Observer

/usr/local/zookeeper/zkdata/zk1# echo 1 > myid/usr/local/zookeeper/zkdata/zk2# echo 2 > myid/usr/local/zookeeper/zkdata/zk3# echo 3 > myid/usr/local/zookeeper/zkdata/zk4# echo 4 > myid

2.0 编写四个zoo.cfg

其中需要改的是:

​ myid的路径,端口号,ip

# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes. 修改对应的zk1 zk2 zk3 zk4dataDir=/usr/local/zookeeper/zkdata/zk1# the port at which the clients will connectclientPort=2181#2001为集群通信端口,3001为集群选举端口,observer(观察者身份)server.1=192.168.200.128:2001:3001 server.2=192.169.200.128:2002:3002 server.3=192.168.200.128:2003:3003 server.4=192.168.200.128:2004:3004:observer

3.0 启动

[root@aliyun bin]# ./zkServer.sh start ../conf/zoo1.cfg[root@aliyun bin]# ./zkServer.sh start ../conf/zoo2.cfg[root@aliyun bin]# ./zkServer.sh start ../conf/zoo3.cfg[root@aliyun bin]# ./zkServer.sh start ../conf/zoo4.cfg

七 : ZAB协议

1.0 ZAB协议介绍

ZAB协议简称:原子广播协议

解决: zk的崩溃恢复和主从数据同步问题

四种节点状态

  • looking: 选举
  • Following:从节点所处的位置
  • leading: 主节点所处的位置
  • observing:观察者所处的位置

2.0 集群启动时leader的选举过程

总结:ZooKeeper 先比较各节点的 ZXID(数据最新程度),ZXID 最大的节点优先;如果相同再比较 服务器ID。各节点不断交换投票,当某个节点获得 超过半数的支持 时当选 Leader。

ZooKeeper 的 Leader 选举在 第一次启动 或 Leader 崩溃 时发生。 假设有3台节点:1,2,3每个节点都要选出一个 Leader。# 一、每个节点刚启动时的状态节点初始状态都是:LOOKING 每个节点会向所有其他节点广播自己的投票: 内容包含:(服务器ID, ZXID)服务器ID: 越大优先级越高 ZXID: 越新(值越大)优先级越高# 二、选举的比较规则(核心)ZooKeeper 使用如下规则决定谁当 Leader: ZXID 最大者优先 如果 ZXID 一样,服务器ID 最大者优先 → 谁的“数据最新 + ID 最大”,谁最有资格当 Leader。# 三、交换投票的过程每个节点先“投给自己” 每个节点收到别人的投票后,会比较: 如果对方的(ZXID, ID)比自己投票更优 → 更新投票为对方 将新的投票再次广播出去# 四、达成多数派(Quorum)当某一个候选人(例如节点3)获得超过半数的票(如3节点中得到2票),则: 节点3成为:LEADING 其他节点变为:FOLLOWING 一个 Leader 选举就完成了。

3.0 崩溃恢复时的leader选举

Leader建立完后,Leader周期性地不断向Follower发送心跳(ping命令,没有内容的socket)。当Leader崩溃后,Follower发现socket通道已关闭,于是Follower开始进入到Looking状态,重新回到上一节中的Leader选举状态,此时集群不能对外提供服务。

4.0 主从数据同步原理

请问:为啥要半数以上呢?

​ 答:保证高效

请问:这个半数指的对象是集群整个还是从节点呢?

​ 答:是集群整个

5.0 NIO和BIO的应用场景

  • NIO

    • 用于被客户端连接的2181端口,使用的是NIO模式与客户端建立连接
    • 客户端开启Watch时,也使用NIO,等待Zookeeper服务器的回调
  • BIO

    • 集群在选举时,多个节点之间的投票通信端口,使用BIO进行通信

八 : CAP理论

1.0 CAP介绍

概念:在一个分布式系统中,一致性(C)可用性(A)、**分区容错性(P)**三者不能同时完全满足,只能同时满足其中两个。

一致性:读到的数据必须是最新正确的

可用性:请求一定有响应

分区容错性:网络一旦分裂,系统不能崩

2.0 BASE定理

BASE 理论(基本可用、软状态、最终一致)

BASE 理论是对 CAP 中AP 系统的一种实现思想,强调牺牲强一致性,换取高可用性和可扩展性。

(1) 基本可用(Basically Available)

​ 系统在出现故障时,整体可用,但可能有降级

​ 例如:高峰期访问慢一点、部分功能被限流,但系统不挂。

(2) 软状态(Soft State)

​ 系统中的数据允许在一段时间内不同步,节点状态不是强一致的。

​ 例如:副本数据不同步,允许“短暂脏读”。

(3) 最终一致性(Eventual Consistency)

​ 虽然不能保证“实时一致”,但经过一定时间后,所有副本最终会达到一致

​ 例如:异步同步、副本延迟,最后一定一致。

(4) 一句话总结(面试最常用):

BASE 理论是分布式系统在 CAP 中选择 AP 的落地方案,牺牲强一致性,换取高可用性,允许数据短暂不一致,但最终会一致。

3.0 zookeeper追求的一致性

​ Zookeeper在数据同步时,追求的并不是强一致性,而是顺序一致性(事务id的单调递增)

1.0 CAP介绍

概念:在一个分布式系统中,一致性(C)可用性(A)、**分区容错性(P)**三者不能同时完全满足,只能同时满足其中两个。

一致性:读到的数据必须是最新正确的

可用性:请求一定有响应

分区容错性:网络一旦分裂,系统不能崩

[外链图片转存中…(img-9NE1Jb89-1765536119292)]

2.0 BASE定理

BASE 理论(基本可用、软状态、最终一致)

BASE 理论是对 CAP 中AP 系统的一种实现思想,强调牺牲强一致性,换取高可用性和可扩展性。

(1) 基本可用(Basically Available)

​ 系统在出现故障时,整体可用,但可能有降级

​ 例如:高峰期访问慢一点、部分功能被限流,但系统不挂。

(2) 软状态(Soft State)

​ 系统中的数据允许在一段时间内不同步,节点状态不是强一致的。

​ 例如:副本数据不同步,允许“短暂脏读”。

(3) 最终一致性(Eventual Consistency)

​ 虽然不能保证“实时一致”,但经过一定时间后,所有副本最终会达到一致

​ 例如:异步同步、副本延迟,最后一定一致。

(4) 一句话总结(面试最常用):

BASE 理论是分布式系统在 CAP 中选择 AP 的落地方案,牺牲强一致性,换取高可用性,允许数据短暂不一致,但最终会一致。

3.0 zookeeper追求的一致性

​ Zookeeper在数据同步时,追求的并不是强一致性,而是顺序一致性(事务id的单调递增)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询