(一)转自 分布式技术原理与实战45讲

邴越

**



在分布式服务中,服务注册和发现是一个特别重要的概念,为什么需要服务注册和发现?常用的服务发现组件有哪些?服务注册和发现对一致性有哪些要求呢?下面我们就来学习服务发现相关的知识。

**

分布式系统下微服务架构的一个重要特性就是可以快速上线或下线,从而可以让服务进行水平扩展,以保证服务的可用性。
假设有一个电商会员服务,随着业务发展,服务器负载越来越高,需要新增服务器。如果没有服务注册与发现,就要把新的服务器地址配置到所有依赖会员模块的服务,并相继重启它们,这显然是不合理的。
服务注册与发现就是保证当服务上下线发生变更时,服务消费者和服务提供者能够保持正常通信。
有了服务注册和发现机制,消费者不需要知道具体服务提供者的真实物理地址就可以进行调用,也无须知道具体有多少个服务者可用;而服务提供者只需要注册到注册中心,就可以对外提供服务,在对外服务时不需要知道具体是哪些服务调用了自己。

**

服务注册和发现的基本流程如下图所示:
image.png
首先,在服务启动时,服务提供者会向注册中心注册服务,暴露自己的地址和端口等,注册中心会更新服务列表。服务消费者启动时会向注册中心请求可用的服务地址,并且在本地缓存一份提供者列表,这样在注册中心宕机时仍然可以正常调用服务。
如果提供者集群发生变更,注册中心会将变更推送给服务消费者,更新可用的服务地址列表。

**

在目前的微服务解决方案中,有三种典型的服务发现组件,分别是 ZooKeeper、Eureka 和 Nacos。

**

ZooKeeper 主要应用在 Dubbo 的注册中心实现,由于 Dubbo 在国内的流行,Dubbo + ZooKeeper 的典型服务化方案,使得 ZooKeeper 成为注册中心的经典解决方案。
ZooKeeper 是一个树形结构的目录服务,支持变更推送。使用 ZooKeeper 实现服务注册,就是应用了这种目录结构。
服务提供者在启动的时候,会在 ZooKeeper 上注册服务。以 com.dubbo.DemoService 为例,注册服务,其实就是在 ZooKeeper 的 /dubbo/com.dubbo.DemoService/providers 节点下创建一个子节点,并写入自己的 URL 地址,这就代表了 com.dubbo.DemoService 这个服务的一个提供者。
服务消费者在启动的时候,会向 ZooKeeper 注册中心订阅服务列表,就是读取并订阅 ZooKeeper 上 /dubbo/com.dubbo.DemoService/providers 节点下的所有子节点,并解析出所有提供者的 URL 地址来作为该服务地址列表。

**

在 Spring Cloud 中,提供了 Eureka 来实现服务发现功能。Eureka 采用的是 Server 和 Client 的模式进行设计,Eureka Server 扮演了服务注册中心的角色,为 Client 提供服务注册和发现的功能。
Eureka Client 通过客户端注册的方式暴露服务,通过注解等方式嵌入到服务提供者的代码中,当服务启动时,服务发现组件会向注册中心注册自身提供的服务,并周期性地发送心跳来更新服务。

image.png

如果连续多次心跳不能够发现服务,那么 Eureka Server 就会将这个服务节点从服务注册表中移除,各个服务之间会通过注册中心的注册信息来实现调用。
Euerka 在 Spring Cloud 中广泛应用,目前社区中集成的是 1.0 版本,在后续的版本更新中,Netflix 宣布 Euerka 2.0 闭源,于是开源社区中也出现了许多新的服务发现组件,比如 Spring Cloud Alibaba Nacos。

**

Nacos 是阿里巴巴推出来的一个开源项目,提供了服务注册和发现功能,使用 Nacos 可以方便地集成 Spring Cloud 框架。如果正在使用 Eureka 或者 Consul,可以通过少量的代码就能迁移到 Nacos 上。
Nacos 的应用和 Eureka 类似,独立于系统架构,需要部署 Nacos Server。除了服务注册和发现之外,Nacos 还提供了配置管理、元数据管理和流量管理等功能,并且提供了一个可视化的控制台管理界面。

image.png

关于 Nacos 的更多应用,可以在 Nacos 官网找到相关的文档。

**

在讨论分布式系统时,一致性是一个绕不开的话题,在服务发现中也是一样。CP 模型优先保证一致性,可能导致注册中心可用性降低,AP 模型优先保证可用性,可能出现服务错误。
为了保证微服务的高可用,避免单点故障,注册中心一般是通过集群的方式来对外服务,比如 ZooKeeper 集群。
ZooKeeper 核心算法是 Zab,实现的是 CP 一致性,所以 ZooKeeper 作为服务发现解决方案,在使用 ZooKeeper 获取服务列表时,如果 ZooKeeper 正在选主,或者 ZooKeeper 集群中半数以上机器不可用时,那么将无法获得数据。
在 Spring Cloud Eureka 中,各个节点都是平等的,几个节点挂掉不影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。只要有一台 Eureka 还在,就能保证注册服务可用,只不过查到的信息可能不是最新的版本,不保证一致性。
Spring Cloud Nacos 在 1.0.0 版本正式支持 AP 和 CP 两种一致性协议,可以动态切换,感兴趣的同学可以去了解一下。
对于服务注册和发现场景来说,一般认为,可用性比数据一致性更加重要。针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不相同,会出现部分提供者地址不存在等,不会导致严重的服务不可用。对于服务消费者来说,能消费才是最重要的,拿到可能不正确的服务实例信息后尝试消费,也要比因为无法获取实例信息而拒绝服务好。

**

这一课时主要分析了服务注册和发现的基本流程、几种典型的服务发现组件,以及在不同服务发现组件中,是如何实现一致性的。
你可以结合实际工作思考一下,目前公司里的服务发现是如何实现的,是自研还是使用开源组件,以及为什么选择这种服务注册和发现方式?