Dubbo-go v3应用级服务发现

Dubbo-go 系列文章(三)

Table of Contents

正如前文提到过的,在大规模的微服务场景下,应用级注册模型相比于接口级注册模型对注册中心的压力更小,这样就很大程度的避免了注册中心的单点故障。

在上一节中,我们提到过接口级注册模型和应用级注册模型在注册中心注册的数据格式发生了根本性的变化,简单来说,在应用级注册模型的注册中心中一行数据代表一个应用实例,其中的数据仅包含必要的定位信息,比如 IP 地址、端口等数据,而接口级元数据信息则需要额外的暴露机制。在 Dubbo-go v3 中,我们使用一种名为“服务自省”完成元数据信息的交换。

接口级元数据

我们之前提到过,应用级注册模型不会将接口级元数据注册在注册中心中,因此需要一个新机制存储这些元数据。在 Dubbo-go v3中,根据元数据信息的存储位置被分为本地模式(local)和远程模式(remote)。

在介绍这两种模式前,我们先来看接口级元数据在 Dubbo-go 中是如何表示的。在 Dubbo-go v3 中,接口级元数据以 URL 的形式呈现,上面的代码中展示了两条接口级元数据,我们首先分析一下它的构成成分。

数据 类型 描述
通讯协议(dubbo) 必要信息
IP 地址(192.168.0.102) 定位信息
端口(20880) 定位信息
接口名(org.apache.dubbo.demo.HelloService) 服务信息
application 接口级元数据信息 该接口所在的应用名
deprecated 接口级元数据信息 该接口是否已经过时
dubbo 接口级元数据信息 dubbo版本
... 接口级元数据信息 ...

除了上表列出的信息外,还有很多其他的接口级元数据信息,受制于篇幅限制这里就不一一讲解了。事实上,承载接口级元数据的 URL 可以不提供 IP 和端口等与实例有关的信息,这些信息是可以从应用级元数据中获取的。但是截止目前的版本,接口级元数据提供的仍然是全量数据

当使用 local 模式时,接口级元数据信息被存储在每个生产者内部并通过内建的 MetadataService 服务向外暴露,本质上 MetadataService 是一个普通 RPC 服务,这意味着任何 consumer 可以通过调用普通 RPC 服务的形式调用 MatadataService。

当使用 remote 模式时,接口级元数据信息被存储在指定的元数据中心。整个模式与注册中心的运行原理基本一致,需要生产者注册元数据信息到元数据中心,然后通过“订阅-通知”机制告知消费者。

ServiceNameMapping

从接口级注册模型到应用级注册模型的改变又引入了一个新问题:消费者如何确定需要调用的接口属于哪个应用呢?Dubbo-go v3 中为了解决这个问题,引入了 ServiceNameMapping 用来保存接口到应用的映射关系。与接口级元数据一样,根据映射数据的存储位置的不同,可以分为本地模式(local)和远程模式(remote)。

本地模式是指用户需要在配置文件中配置这种映射关系。为什么可以在本地以硬编码的方式配置这种映射关系呢?首先,这种映射关系是相对稳定的,一个应用提供的接口基本上不会变动。其次,用户大概率是知道这种映射关系的,即用户知道应用提供哪些接口。所以基于这两点可以允许用户在本地配置这种关系。在 Dubbo-go v3 中,可以在配置文件中使用 provided_by 关键词设置,下面的配置文件表明了 org.apache.dubbo.Greeter 接口由 application1 应用提供。

远程模式则需要生产者在启动时将“应用-接口”映射关系写入元数据中心,实现动态的更新映射的目的。在这种模式下,我们需要考虑在应用更新后接口级元数据也可能被更新,那客户端何时去元数据中心拉取最新的元数据呢?一个应用被更新后,那么应用级元数据信息一定会被更新,因为应用级元数据存储着应用版本等信息,此时它的接口级元数据可能会被改变,因此选择在注册中心通知消费者时更新接口级元数据是最合适的。

架构

在 Dubbo-go v3 中,整个架构相比于 Dubbo-go v1.5 结构更加复杂,特别是元数据订阅与获取部分,所以在本节中将重点讲解整个架构是如何工作的。

上图展示了整个架构的概览,为了统一过程,接口级元数据和 ServiceNameMapping 都是用本地模式。类比我们在上一节中展示的接口级服务发现与注册模型的架构图,最大的差异主要表现在 Provider 侧,我们人为的将 Provider 提供的服务分为元数据服务(MetadataService)和普通服务(RPCService 1, ..., RPCService N)。

在 Dubbo-go v3 版本中,系统的调用步骤主要分为9个步骤:

  • 生产者初始化阶段

    1. 在初始化阶段,系统自动收集 RPC 服务暴露信息,将信息交由 MetadataService,最后将 MetadataService 按照普通的 RPC 服务向外暴露;
    2. 生产者将应用级信息注册到注册中心;
  • 应用级元数据获取阶段

    1. 根据接口名获取应用名,这里应用名表示唯一的一个应用;
    2. 订阅应用级元数据;
    3. 注册中心通知应用元数据变更,消费者更新应用级元数据;
  • 接口级元数据获取阶段(服务自省阶段)

    1. 以普通 RPC 调用方式向生产者的 MetadataService 发起调用;
    2. MetadataService 返回接口级元数据;
  • 调用阶段

    1. 向普通 RPC 服务发起调用;
    2. 返回调用结果。

其中最特别的就是服务自省阶段,接口级元数据的交换是生产者和消费者自行协商,接口级元数据不在需要借助注册中心分发,极大减轻了注册中心的压力。