前言
一线大厂ZooKeeper的十二连问,你顶得了嘛?
本文曾经收录到github
https://github.com/whx123/Jav...
1. 面试官:工作中应用过Zookeeper嘛?你晓得它是什么,有什么用处呢?
小菜鸡的我:
- 有应用过的,应用ZooKeeper作为dubbo的注册核心,应用ZooKeeper实现分布式锁。
- ZooKeeper,它是一个开放源码的分布式协调服务,它是一个集群的管理者,它将简略易用的接口提供给用户。
- 能够基于Zookeeper 实现诸如数据公布/订阅、负载平衡、命名服务、分布式协调/告诉、集群治理、Master 选举、分布式锁和分布式队列等性能。
- Zookeeper的用处:命名服务、配置管理、集群治理、分布式锁、队列治理
用处跟性能不是一个意思咩?给我一个眼神,让我本人领会
2. 面试官:说下什么是命名服务,什么是配置管理,又什么是集群治理吧
小菜鸡的我(幸好我刷过面试题),无所畏惧
- 命名服务就是:
命名服务是指通过指定的名字来获取资源或者服务地址。Zookeeper能够创立一个全局惟一的门路,这个门路就能够作为一个名字。被命名的实体能够是集群中的机器,服务的地址,或者是近程的对象等。一些分布式服务框架(RPC、RMI)中的服务地址列表,通过应用命名服务,客户端利用可能依据特定的名字来获取资源的实体、服务地址和提供者信息等。
- 配置管理: :
理论我的项目开发中,咱们常常应用.properties或者xml须要配置很多信息,如数据库连贯信息、fps地址端口等等。因为你的程序个别是分布式部署在不同的机器上(如果你是单机利用当我没说),如果把程序的这些配置信息保留在zk的znode节点下,当你要批改配置,即znode会发生变化时,能够通过扭转zk中某个目录节点的内容,利用watcher告诉给各个客户端,从而更改配置。
- 集群治理
集群治理包含集群监控和集群管制,其实就是监控集群机器状态,剔除机器和退出机器。zookeeper能够不便集群机器的治理,它能够实时监控znode节点的变动,一旦发现有机器挂了,该机器就会与zk断开连接,对用的长期目录节点会被删除,其余所有机器都收到告诉。新机器退出也是相似酱紫,所有机器收到告诉:有新兄弟目录退出啦。
3. 面试官:你提到了znode节点,那你晓得znode有几种类型呢?zookeeper的数据模型是怎么的呢?
小菜鸡的我(我先想想):
zookeeper的数据模型
ZooKeeper的视图数据结构,很像Unix文件系统,也是树状的,这样能够确定每个门路都是惟一的。zookeeper的节点对立叫做znode,它是能够通过门路来标识,结构图如下:
znode的4种类型
依据节点的生命周期,znode能够分为4种类型,别离是长久节点(PERSISTENT)、长久程序节点(PERSISTENT_SEQUENTIAL)、长期节点(EPHEMERAL)、长期程序节点(EPHEMERAL_SEQUENTIAL)
- 长久节点(PERSISTENT)
这类节点被创立后,就会始终存在于Zk服务器上。直到手动删除。
- 长久程序节点(PERSISTENT_SEQUENTIAL)
它的根本个性同长久节点,不同在于减少了程序性。父节点会保护一个自增整性数字,用于子节点的创立的先后顺序。
- 长期节点(EPHEMERAL)
长期节点的生命周期与客户端的会话绑定,一旦客户端会话生效(非TCP连贯断开),那么这个节点就会被主动清理掉。zk规定长期节点只能作为叶子节点。
- 长期程序节点(EPHEMERAL_SEQUENTIAL)
根本个性同长期节点,增加了程序的个性。
4、面试官:你晓得znode节点外面存储的是什么吗?每个节点的数据最大不能超过多少呢?
小菜鸡的我:
znode节点外面存储的是什么?
Znode数据节点的代码如下
public class DataNode implements Record { byte data[]; Long acl; public StatPersisted stat; private Set<String> children = null; }
哈哈,Znode蕴含了存储数据、拜访权限、子节点援用、节点状态信息,如图:
- data: znode存储的业务数据信息
- ACL: 记录客户端对znode节点的拜访权限,如IP等。
- child: 以后节点的子节点援用
- stat: 蕴含Znode节点的状态信息,比方事务id、版本号、工夫戳等等。
每个节点的数据最大不能超过多少呢
为了保障高吞吐和低提早,以及数据的一致性,znode只适宜存储十分小的数据,不能超过1M,最好都小于1K。
5、面试官:你晓得znode节点上的监听机制嘛?讲下Zookeeper watch机制吧。
小菜鸡的我:
- Watcher机制
- 监听机制的工作原理
- Watcher个性总结
Watcher监听机制
Zookeeper 容许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件告诉来实现分布式的告诉性能,而后客户端依据 Watcher告诉状态和事件类型做出业务上的扭转。
能够把Watcher了解成客户端注册在某个Znode上的触发器,当这个Znode节点发生变化时(增删改查),就会触发Znode对应的注册事件,注册的客户端就会收到异步告诉,而后做出业务的扭转。
Watcher监听机制的工作原理
- ZooKeeper的Watcher机制次要包含客户端线程、客户端 WatcherManager、Zookeeper服务器三局部。
- 客户端向ZooKeeper服务器注册Watcher的同时,会将Watcher对象存储在客户端的WatchManager中。
- 当zookeeper服务器触发watcher事件后,会向客户端发送告诉, 客户端线程从 WatcherManager 中取出对应的 Watcher 对象来执行回调逻辑。
Watcher个性总结
- 一次性:一个Watch事件是一个一次性的触发器。一次性触发,客户端只会收到一次这样的信息。
- 异步的: Zookeeper服务器发送watcher的告诉事件到客户端是异步的,不能冀望可能监控到节点每次的变动,Zookeeper只能保障最终的一致性,而无奈保障强一致性。
- 轻量级: Watcher 告诉非常简单,它只是告诉产生了事件,而不会传递事件对象内容。
- 客户端串行: 执行客户端 Watcher 回调的过程是一个串行同步的过程。
- 注册 watcher用getData、exists、getChildren办法
- 触发 watcher用create、delete、setData办法
6、面试官:你对Zookeeper的数据结构都有肯定理解,那你讲下Zookeeper的个性吧
小菜鸡的我:(我背过书,啊哈哈)
Zookeeper 保障了如下分布式一致性个性:
- 程序一致性:从同一客户端发动的事务申请,最终将会严格地依照程序被利用到 ZooKeeper 中去。
- 原子性:所有事务申请的处理结果在整个集群中所有机器上的利用状况是统一的,也就是说,要么整个集群中所有的机器都胜利利用了某一个事务,要么都没有利用。
- 繁多视图:无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是统一的。
- 可靠性: 一旦服务端胜利地利用了一个事务,并实现对客户端的响应,那么该事务所引起的服务端状态变更将会被始终保留下来。
- 实时性(最终一致性): Zookeeper 仅仅能保障在肯定的时间段内,客户端最终肯定可能从服务端上读取到最新的数据状态。
7、面试官:你刚提到程序一致性,那zookeeper是如何保障事务的程序一致性的呢?
小菜鸡的我:(完蛋了这题不会)
这道题能够看下这篇文章(本题答案来自该文章):聊一聊ZooKeeper的程序一致性
须要理解事务ID,即zxid。ZooKeeper的在选举时通过比拟各结点的zxid和机器ID选出新的主结点的。zxid由Leader节点生成,有新写入事件时,Leader生成新zxid并随提案一起播送,每个结点本地都保留了以后最近一次事务的zxid,zxid是递增的,所以谁的zxid越大,就示意谁的数据是最新的。
ZXID的生成规定如下:
ZXID有两局部组成:
- 任期:实现本次选举后,直到下次选举前,由同一Leader负责协调写入;
- 事务计数器:枯燥递增,每失效一次写入,计数器加一。
ZXID的低32位是计数器,所以同一任期内,ZXID是间断的,每个结点又都保留着本身最新失效的ZXID,通过比照新提案的ZXID与本身最新ZXID是否相差“1”,来保障事务严格依照程序失效的。
8、面试官:你提到了Leader,你晓得Zookeeper的服务器有几种角色嘛?Zookeeper下Server工作状态又有几种呢?
小菜鸡的我:
Zookeeper 服务器角色
Zookeeper集群中,有Leader、Follower和Observer三种角色
Leader
Leader服务器是整个ZooKeeper集群工作机制中的外围,其次要工作:
- 事务申请的惟一调度和解决者,保障集群事务处理的程序性
- 集群外部各服务的调度者
Follower
Follower服务器是ZooKeeper集群状态的跟随者,其次要工作:
- 解决客户端非事务申请,转发事务申请给Leader服务器
- 参加事务申请Proposal的投票
- 参加Leader选举投票
Observer
Observer是3.3.0 版本开始引入的一个服务器角色,它充当一个观察者角色——察看ZooKeeper集群的最新状态变动并将这些状态变更同步过去。其工作:
- 解决客户端的非事务申请,转发事务申请给 Leader 服务器
- 不参加任何模式的投票
Zookeeper下Server工作状态
服务器具备四种状态,别离是 LOOKING、FOLLOWING、LEADING、OBSERVING。
- 1.LOOKING:寻找Leader状态。当服务器处于该状态时,它会认为以后集群中没有 Leader,因而须要进入 Leader 选举状态。
- 2.FOLLOWING:跟随者状态。表明以后服务器角色是Follower。
- 3.LEADING:领导者状态。表明以后服务器角色是Leader。
- 4.OBSERVING:观察者状态。表明以后服务器角色是Observer。
9、面试官:你说到服务器角色是基于ZooKeeper集群的,那你画一下ZooKeeper集群部署图吧?ZooKeeper是如何保障主从节点数据一致性的呢?
小菜鸡的我:
ZooKeeper集群部署图
ZooKeeper集群是一主多从的构造:
- 如果是写入数据,先写入主服务器(主节点),再告诉从服务器。
- 如果是读取数据,既读主服务器的,也能够读从服务器的。
ZooKeeper如何保障主从节点数据一致性
咱们晓得集群是主从部署构造,要保障主从节点一致性问题,无非就是两个次要问题:
- 主服务器挂了,或者重启了
- 主从服务器之间同步数据~
Zookeeper是采纳ZAB协定(Zookeeper Atomic Broadcast,Zookeeper原子播送协定)来保障主从节点数据一致性的,ZAB协定反对解体复原和音讯播送两种模式,很好解决了这两个问题:
- 解体复原:Leader挂了,进入该模式,选一个新的leader进去
- 音讯播送: 把更新的数据,从Leader同步到所有Follower
Leader服务器挂了,所有集群中的服务器进入LOOKING状态,首先,它们会选举产生新的Leader服务器;接着,新的Leader服务器与集群中Follower服务进行数据同步,当集群中超过半数机器与该 Leader服务器实现数据同步之后,退出恢复模式进入音讯播送模式。Leader 服务器开始接管客户端的事务申请生成事务Proposal进行事务申请解决。
10、面试官:Leader挂了,进入解体复原,是如何选举Leader的呢?你讲一下ZooKeeper选举机制吧
小菜鸡的我:
服务器启动或者服务器运行期间(Leader挂了),都会进入Leader选举,咱们来看一下~假如当初ZooKeeper集群有五台服务器,它们myid别离是服务器1、2、3、4、5,如图:
服务器启动的Leader选举
zookeeper集群初始化阶段,服务器(myid=1-5)顺次启动,开始zookeeper选举Leader~
- 服务器1(myid=1)启动,以后只有一台服务器,无奈实现Leader选举
- 服务器2(myid=2)启动,此时两台服务器可能互相通信,开始进入Leader选举阶段
- 每个服务器收回一个投票
服务器1 和 服务器2都将本人作为Leader服务器进行投票,投票的根本元素包含:服务器的myid和ZXID,咱们以(myid,ZXID)模式示意。初始阶段,服务器1和服务器2都会投给本人,即服务器1的投票为(1,0),服务器2的投票为(2,0),而后各自将这个投票发给集群中的其余所有机器。
- 承受来自各个服务器的投票
每个服务器都会承受来自其余服务器的投票。同时,服务器会校验投票的有效性,是否本轮投票、是否来自LOOKING状态的服务器。
- 解决投票
收到其余服务器的投票,会将被人的投票跟本人的投票PK,PK规定如下:
- 优先查看ZXID。ZXID比拟大的服务器优先作为leader。
- 如果ZXID雷同的话,就比拟myid,myid比拟大的服务器作为leader。
服务器1的投票是(1,0),它收到投票是(2,0),两者zxid都是0,因为收到的myid=2,大于本人的myid=1,所以它更新本人的投票为(2,0),而后从新将投票收回去。对于服务器2呢,即不再须要更新本人的投票,把上一次的投票信息收回即可。
- 统计投票
每次投票后,服务器会统计所有投票,判断是否有过半的机器承受到雷同的投票信息。服务器2收到两票,少于3(n/2+1,n为总服务器),所以持续放弃LOOKING状态
- 服务器3(myid=3)启动,持续进入Leader选举阶段
跟后面流程统一,服务器1和2先投本人一票,因为服务器3的myid最大,所以大家把票改投给它。此时,服务器为3票(大于等于n/2+1),所以服务器3入选为Leader。 服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
- 服务器4启动,发动一次选举。
此时服务器1,2,3曾经不是LOOKING状态,不会更改选票信息。选票信息后果:服务器3为4票,服务器4为1票。服务器4并更改状态为FOLLOWING;
- 服务器5启动,发动一次选举。
同理,服务器也是把票投给服务器3,服务器5并更改状态为FOLLOWING;
- 投票完结,服务器3入选为Leader
服务器运行期间的Leader选举
zookeeper集群的五台服务器(myid=1-5)正在运行中,忽然某个霎时,Leader服务器3挂了,这时候便开始Leader选举~
- 1.变更状态
Leader 服务器挂了之后,余下的非Observer服务器都会把本人的服务器状态更改为LOOKING,而后开始进入Leader选举流程。
- 2.每个服务器发动投票
每个服务器都把票投给本人,因为是运行期间,所以每台服务器的ZXID可能不雷同。假如服务1,2,4,5的zxid别离为333,666,999,888,则别离产生投票(1,333),(2,666),(4,999)和(5,888),而后各自将这个投票发给集群中的其余所有机器。
- 3.承受来自各个服务器的投票
- 4.解决投票
投票规定是跟Zookeeper集群启动期间统一的,优先查看ZXID,大的优先作为Leader,所以显然服务器zxid=999具备优先权。
- 5.统计投票
- 6.扭转服务器状态
11、面试官: 你后面提到在我的项目中应用过Zookeeper的分布式锁,讲一下zk分布式锁的实现原理吧?
小菜鸡的我:
Zookeeper就是应用长期程序节点个性实现分布式锁的。
- 获取锁过程 (创立长期节点,查看序号最小)
- 开释锁 (删除长期节点,监听告诉)
获取锁过程
- 当第一个客户端申请过去时,Zookeeper客户端会创立一个长久节点/locks。如果它(Client1)想取得锁,须要在locks节点下创立一个程序节点lock1.如图
- 接着,客户端Client1会查找locks上面的所有长期程序子节点,判断本人的节点lock1是不是排序最小的那一个,如果是,则胜利取得锁。
- 这时候如果又来一个客户端client2前来尝试取得锁,它会在locks下再创立一个长期节点lock2
- 客户端client2一样也会查找locks上面的所有长期程序子节点,判断本人的节点lock2是不是最小的,此时,发现lock1才是最小的,于是获取锁失败。获取锁失败,它是不会甘心的,client2向它排序靠前的节点lock1注册Watcher事件,用来监听lock1是否存在,也就是说client2抢锁失败进入期待状态。
- 此时,如果再来一个客户端Client3来尝试获取锁,它会在locks下再创立一个长期节点lock3
- 同样的,client3一样也会查找locks上面的所有长期程序子节点,判断本人的节点lock3是不是最小的,发现自己不是最小的,就获取锁失败。它也是不会甘心的,它会向在它后面的节点lock2注册Watcher事件,以监听lock2节点是否存在。
开释锁
咱们再来看看开释锁的流程,zookeeper的客户端业务实现或者故障,都会删除长期节点,开释锁。如果是工作实现,Client1会显式调用删除lock1的指令
如果是客户端故障了,依据长期节点得个性,lock1是会主动删除的
lock1节点被删除后,Client2可开心了,因为它始终监听着lock1。lock1节点删除,Client2立即收到告诉,也会查找locks上面的所有长期程序子节点,发下lock2是最小,就取得锁。
同理,Client2取得锁之后,Client3也对它虎视眈眈,啊哈哈~
12. 面试官:好的,最初一道题,你说说dubbo和Zookeeper的关系吧,为什么抉择Zookeeper作为注册核心?
小菜鸡的我(答了这么多道题,不会还不给我过吧?):
dubbo的注册核心能够选Zookeeper,memcached,redis等。为什么抉择Zookeeper,因为它的性能个性咯~
- 命名服务,服务提供者向Zookeeper指定节点写入url,实现服务公布。
- 负载平衡,注册核心的承载能力无限,而Zookeeper集群配合web利用很容易达到负载平衡。
- zk反对监听事件,特地适宜公布/订阅的场景,dubbo的生产者和消费者就相似这场景。
- 数据模型简略,数据存在内存,堪称高性能
- Zookeeper其余特点都能够搬出来讲一下~
集体公众号
参考与感激
- <<从Paxos到Zookeeper 分布式一致性原理与实际>>
- zookeeper面试题
- 28道进阶必备ZooKeeper面试真题(倡议珍藏!)
- 漫画:什么是ZooKeeper?
- 聊一聊ZooKeeper的程序一致性
- Zookeeper——一致性协定:Zab协定
- Zookeeper的选举机制原理(图文深度解说)
- 漫画:如何用Zookeeper实现分布式锁?