【面试精选】ZooKeeper 的典型应用场景发布订阅功能有啥用?

来自:JavaGuide(微信号:Java_Guide),作者:SnailClimb

稍微对 ZooKeeper 有点了解的应该都知道 ZooKeeper 的典型应用场景之一就是提供 “发布订阅服务”。利用 “发布订阅服务”我们可以利用 ZooKeeper 实现两种常见的功能:

①作为配置中心;

②作为Dubbo 的注册中心也就是发布订阅中心。

作为配置中心

很多时候我们相同的程序可能部署在多台机器上提升性能,不同的程序也可能有相同的配置文件。如果我们每次修改配置文件,都要一个一个机器修改的话,那么必定非常麻烦。我们可以考虑把应用配置放到 ZooKeeper 上去,也就是保存在 Zookeeper 的某个目录节点中,我们对指定的节点设置一个 Watcher 监听 ,这样做的好处就是:一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后可以从 Zookeeper 获取新的配置信息应用到系统中就好。

举个简单的例子(需要使用 API 操作 ZooKeeper ,我这里不会涉及API操作的相关内容,网上有很多这样的文章,我后面也可能会总结一篇这样的文章),我们的数据库配置信息可能会同时被多台机器上的程序所使用,为了便于统一管理,我们可以在 ZooKeeper 上创建一个数据节点比如:/config/databaseconfig,然后我们将我们的数据库配置信息写入到该数据节点中去。


集群中每台机器在启动初始化阶段,首先会从上面提到的Zookeeper配置节点上读取数据库信息,同时,客户端还需要在该配置节点上注册一个 Watcher 监听,一旦发生节点数据变更,所有订阅的客户端都能够获取到数据变更通知。


在系统运行过程中,可能会出现需要进行数据库切换的情况,这个时候就需要进行配置变更。借助Zookeeper,我们只需要对ZooKeeper上配置节点的内容进行更新,就能够帮我们将数据变更的通知发送到各个客户端,每个客户端在接收到这个变更通知后,就可以重新进行最新数据的获取。

ZooKeeper 中利用 Watcher 机制实现分布式通知功能,Zookeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。

作为 Dubbo 的注册中心

Zookeeper 一个非常常用的使用场景就是用于担任服务生产者和服务消费者的注册中心提供发布订阅服务。 服务生产者将自己提供的服务注册到 Zookeeper 的一个或一系列节点上去,服务的消费者在进行服务调用的时候先到 Zookeeper 中查找服务,获取到服务生产者的详细信息之后,再去调用服务生产者的内容与数据。如下图所示,在 Dubbo架构中 Zookeeper 就担任了注册中心这一角色。

Dubbo

我以《使用 SpringBoot+Dubbo 搭建一个简单分布式服务》 这篇文章中的 top.snailclimb.service 包下的HelloService 接口为例,没有看过这篇文章的也不要紧,我下面简单给大家说一下就行了。

先来看看示例项目包括哪几部分,如下图所示:

项目概要

大家只需知道top.snailclimb.service 是 dubbo-interface 中的一个包,这个包里面有一些接口,这些接口会在 provider 端被实现,然后在 consumer 端被调用或者说是消费(可多次消费,只要服务提供者还在线)。

先来看一下 Dubbo 使用 ZooKeeper 当做注册中心的节点示意图。

Dubbo 使用 ZooKeeper 当做注册中心的节点示意图


下面我们来看看 Dubbo 基于 ZooKeeper 实现的注册中心的工作流程。

如果服务是第一次启动,那么对于服务提供者会经历下面几步:

  1. 首先会创建dubbo 根目录;

  2. 再在dubbo根目录下创建服务节点top.snailclimb.service.HelloService(代表 Dubbo 的一个服务);

  3. 然后再在服务节点top.snailclimb.service.HelloService下创建 consumers(代表一个服务的真正消费者)、providers(代表一个服务的真正提供者)、configurators、routers这4个节点,如上图所示;

  4. 最后会在/dubbo/top.snailclimb.service.HelloService/providers节点下创建一个子节点,并写人自己的URL地址。

如果服务不是第一次启动了,并且没有增加、修改或者减少服务的话,就会直接从上面提到的第 4 步开始。

服务消费者在启动的时候,读取并订阅 ZooKeeper 上 /dubbo/top.snailclimb.service.HelloService /providers 节点下的所有子节点,并解析出其中的 URL 地址作为该服务地址列表,然后程序就可以调用了。同时,服务消费者还会在 /dubbo/top.snailclimb.service.HelloService /consumers节点下
创建一个临时节点,并写人自己的 URL 地址,这就代表了top.snailclimb.service.HelloService 这个服务的一个消费者。

通过我们上一节《ZooKeeper数据模型和常见命令》学过的常见命令来验证一下!

查看根目录下存在哪些节点,可以看到的确有 dubbo 。

[zk: 127.0.0.1:2181(CONNECTED) 0] ls / 
[dubbo, zookeeper, node1]

查看 dubbo 节点下有哪些节点,可以看到我们的top.snailclimb.service.HelloService 节点 就在里面

[zk: 127.0.0.1:2181(CONNECTED) 1] ls /dubbo
[top.snailclimb.service.HelloService]

再看一下top.snailclimb.service.HelloService 节点下有哪些节点,可以看到我们上图描述的 4 个节点也在里面。

[zk: 127.0.0.1:2181(CONNECTED) 3] ls /dubbo/top.snailclimb.service.HelloService 
[consumers, configurators, routers, providers]

当生产者启动后会在相应的 service 目录的 provicers 目录记录它的信息比如暴露出来的端口和地址

url 地址

推荐↓↓↓
Java编程
上一篇:看似很简单的几个Java概念,你真的搞清了吗? 下一篇:利用策略模式优化过多 if else 代码