一、模拟面试
终于来到重头戏了,本小节我会从网上找到一些关于 ZK 的面试题进行剖析讲解,并且站在面试官的基础上分析考点,相信看完这一节,出去面试再碰到 ZK 相关的问题你便能披荆斩棘、所向披靡!
我先给大家模拟一个面试的场景:
面试官:我看你简历上用过 ZK,能给我介绍下吗?你是怎么理解 ZK 的作用呢?
(如果你把百度百科中的定义背给他听,我只能说 666,千万别这样,会被别人当成傻子。)
我:我的理解 ZK 是一个脱离于应用的第三方进程,类似的数据库,消息队列,Redis 等都是扮演这个角色,拥有一定的数据存储和查询能力,可以让我们在现在都是分布式部署的应用之间“传递”数据,其次 ZK 支持的回调通知,让应用可以在一些业务场景中感知到数据的变化并及时作出相应的反应。最后,ZK 本身也支持集群部署具有高可用的特点,是一个可靠的第三方中间件。
面试官:嗯,你刚刚提到了回调通知,能仔细跟我聊聊 ZK 是怎么去实现的吗?
我:各种编程语言的客户端都会对这个回调通知进行抽象,通常需要开发者声明一个 callback 的对象,在 Java 的客户端中这个接口是 Watcher,ZK 服务端提供了一些方法,比如 getData、exists 或者最新版本中的 addWatch 都可以用来向 ZK 注册回调通知,而向服务端发送的回调通知,只会告诉服务端我当前的这个路径需要被通知,服务端得知后,会在内存中记录下来,路径和客户端之间的关系,客户端自己也需要记录下来,路径和具体回调的关系。当被订阅的路径发生事件的时候,各种增删改吧,服务端就会从内存中的记录去查看有没有需要通知的客户端,有的话会发送一个通知的请求给客户端,客户端收到通知后,就会从本地的记录中取出对应的回调对象去执行 callback 方法!
(实际情况,我觉得面试官可能不会让你一直说下去,应该是互相聊的一个状态)
面试官:嗯,说得挺详细,那你刚刚提到的 getData、exists、 addWatch 三种注册有什么区别吗?
我:getData、exists 以及 getChildren 注册的通知都是一次性的,当服务端通知过一次后,就会删除内存中的记录,之后如果仍然需要通知的话,客户端就要去继续注册,而 addWatch 注册的回调通知是永久性的,只需要注册一次可以一直被通知。
面试官:嗯好,你刚刚还提到了 ZK 有一定的数据存储能力,你能说说 ZK 是怎么保存和整理数据的吗?
我:ZK 的数据体现在两部分。
面试官:哦?哪两部分?
我:内存中和磁盘上。
面试官:那你先说说内存里 ZK 是怎么存储数据
我:从逻辑上来讲,ZK 内存中的数据其实是一个树形结构,从 / 根节点开始,逐级向下用 / 分割,每一个节点下面还可以有多个子节点,就类似于 Unix 中的目录结构,但在实际中,ZK 是使用一个 HashMap 去存储整个树形结构的数据的,key 是对应的全路径字符串,value 则是一个节点对象,包含了节点的各种信息。
面试官:能说说你觉得为什么要这么设计吗?
(其实我觉得一般面试官不会这么问,以下回答也是我个人的猜想)