微服务-注册中心

在落地注册中心的过程中,我们需要解决一系列的问题,包括 如何存储服务信息、如何注册节点、如何反注册、如何查询节点信息以及如何订阅服务变更等。

注册中心如何存储服务信息

注册中心既然是用来存储服务信息的,那么服务信息都包含哪些内容呢?

一般包含三部分内容:

  • 分组、
  • 服务名
  • 节点信息,又包括节点地址和节点其他信息

一般是按照“服务 - 分组 - 节点信息”三层结构来存储,Service 代表服务的具体分组,Cluster 代表服务的接口名,节点信息用 KV 存储。

微服务-注册中心

搞清楚了注册中心存储服务信息的原理后,再来看**册中心具体是如何工作的,包括四个 流程。

服务提供者注册流程。

服务提供者反注册流程。

服务消费者查询流程。

服务消费者订阅变更流程。

接下来,我来给你具体讲解上面四个流程的实现方式。

注册中心是如何工作的

1. 如何注册节点

知道了服务的节点信息如何存储之后,服务注册流程是怎么样的呢?可以用下面这张流程图 来描述。

根据我的经验,服务注册流程主要有下面几个步骤:

首先查看要注册的节点是否在白名单内?如果不在就抛出异常,在的话继续下一步。

其次要查看注册的 Cluster(服务的接口名)是否存在?如果不存在就抛出异常,存在的 话继续下一步。

然后要检查 Service(服务的分组)是否存在?如果不存在则抛出异常,存在的话继续下 一步。

最后将节点信息添加到对应的 Service 和 Cluster 下面的存储中。

2. 如何反注册

再来看下服务提供者节点反注册的流程,可以用下面这张流程图来描述。

根据我的经验,节点反注册流程主要包含下面几个步骤:

查看 Service(服务的分组)是否存在,不存在就抛出异常,存在就继续下一步。 查看 Cluster(服务的接口名)是否存在,不存在就抛出异常,存在就继续下一步。 删除存储中 Service 和 Cluster 下对应的节点信息。
更新 Cluster 的 sign 值。

3. 如何查询节点信息

关于服务消费者是如何从注册中心查询服务提供者的节点信息,可以用下面这张流程图来描 述。

服务消费者查询节点信息主要分为下面几个步骤:

首先从 localcache(本机内存)中查找,如果没有就继续下一步。这里为什么服务消费 者要把服务信息存在本机内存呢?主要是因为服务节点信息并不总是时刻变化的,并不需 要每一次服务调用都要调用注册中心获取最新的节点信息,只需要在本机内存中保留最新 的服务提供者的节点列表就可以。

接着从 snapshot(本地快照)中查找,如果没有就继续下一步。这里为什么服务消费者 要在本地磁盘存储一份服务提供者的节点信息的快照呢?这是因为服务消费者同注册中心 之间的网络不一定总是可靠的,服务消费者重启时,本机内存中还不存在服务提供者的节 点信息,如果此时调用注册中心失败,那么服务消费者就拿不到服务节点信息了,也就没 法调用了。本地快照就是为了防止这种情况的发生,即使服务消费者重启后请求注册中心 失败,依然可以读取本地快照,获取到服务节点信息。

4. 如何订阅服务变更

最后看下,服务消费者如何订阅服务提供者的变更信息呢?可以用下面这张流程图来描述。

微服务-注册中心

主要分为下面几个步骤:

服务消费者从注册中心获取了服务的信息后,就订阅了服务的变化,会在本地保留 Cluster 的 sign 值。

服务消费者每隔一段时间,调用 getSign() 函数,从注册中心获取服务端该 Cluster 的 sign 值,并与本地保留的 sign 值做对比,如果不一致,就从服务端拉取新的节点信息, 并更新 localcache 和 snapshot。

这里小结一下,以上就是服务注册和反注册、服务查询和服务订阅变更的基本流程。除此之 外,我再给你讲下我在实际项目实践中,实现服务注册与发现时遇到的几个问题,希望能给 你帮助。

注册与发现的几个问题

1. 多注册中心

对于服务消费者来说,要能够同时从多个注册中心订阅服务;对于服务提供者来 说,要能够同时向多个注册中心注册服务。

2. 并行订阅服务

并行订阅的方式,每订阅一个服务就单独用一个线程来处理,这样的话即使 遇到个别服务节点连接超时,其他服务节点的初始化连接也不受影响,最慢也就是这个服务 节点的初始化连接耗费的时间,最终所有服务节点的初始化连接耗时控制在了 30 秒以内。

3. 批量反注册服务

需要定时去清理注册中心中的“僵尸节点”。后来我 们通过优化反注册逻辑,对于下线机器、节点销毁的场景,通过调用注册中心提供的批量反 注册接口,一次调用就可以把该节点上提供的所有服务同时反注册掉,从而避免了“僵尸节 点”的出现。

4. 服务变更信息增量更新

为了减少服务消费者从注册中心中拉取的服务可用节点信息的数据量,这个时候可以通过增 量更新的方式,注册中心只返回变化的那部分节点信息,尤其在只有少数节点信息变更时,

此举可以大大减少服务消费者从注册中心拉取的数据量,从而最大程度避免产生网络风暴。

开源服务注册中心如何选型

 

当下主流的服务注册与发现的解决方案,主要有两种:

  • 应用内注册与发现:注册中心提供服务端和客户端的 SDK,业务应用通过引入注册中心 提供的 SDK,通过 SDK 与注册中心交互,来实现服务的注册和发现。
  • 应用外注册与发现:业务应用本身不需要通过 SDK 与注册中心打交道,而是通过其他方 式与注册中心交互,间接完成服务注册与发现。
注册中心选型要考虑的两个问题

在选择注册中心解决方案的时候,除了要考虑是采用应用内注册还是应用外注册的方式以 外,还有两个最值得关注的问题,一个是高可用性,一个是数据一致性,下面我来给你详细 解释下为什么。

  1. 高可用性
  2. 数据一致性

两种典型的注册中心实现

1. 应用内

采用应用内注册与发现的方式,最典型的案例要属 Netflix 开源的 Eureka,官方架构图如 下。

Eureka Server:注册中心的服务端,实现了服务信息注册、存储以及查询等功能。

服务端的 Eureka Client:集成在服务端的注册中心 SDK,服务提供者通过调用 SDK, 实现服务注册、反注册等功能。

客户端的 Eureka Client:集成在客户端的注册中心 SDK,服务消费者通过调用 SDK, 实现服务订阅、服务更新等功能。

2. 应用外

采用应用外方式实现服务注册和发现,最典型的案例是开源注册中心 Consul,它的架构图 如下。

(https://technologyconversations.files.wordpress.com/2015/09/etcd-registrator- confd2.png)

通过这张架构图,可以看出来使用 Consul 实现应用外服务注册和发现主要依靠三个重要的 组件:

Consul:注册中心的服务端,实现服务注册信息的存储,并提供注册和发现服务。

Registrator:一个开源的第三方服务管理器项目,它通过监听服务部署的 Docker 实例 是否存活,来负责服务提供者的注册和销毁。

Consul Template:定时从注册中心服务端获取最新的服务提供者节点列表并刷新 LB 配 置(比如 Nginx 的 upstream),这样服务消费者就通过访问 Nginx 就可以获取最新的 服务提供者信息。