Dubbo3.0应用级服务注册原理

作者:Sample HubSpot User | Nov 17, 2023 3:28:21 AM

作者:周起仝  职位:后端工程师

背景

Dubbo作为一款RPC服务通讯框架,自2017年重新开源以来,目前已经迭代到了3.1.0版本。3.0基于Dubbo 2.x演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级,其中最主要的特性是为了适配云原生而引入的应用级服务发现模型。

1、什么是应用级服务注册?

了解应用级服务发现之前我们先来清楚什么是接口级服务注册发现?在3.0以前Dubbo虽然在异步化改造、服务治理、三大中心方面做了大量的优化和迭代升级,但是一直是面向接口的服务注册发现,主要体现在Dubbo2.x通过将接口的信息注册到注册中心,此种注册模型属于接口级服务注册发现,也就是以接口为粒度将接口信息注册到注册中心,订阅者也是以接口的粒度实现服务发现。

了解了接口级服务注册发现之后,Dubbo3.0做了一个巨大的改造,将服务注册粒度从接口级变为应用级,也就是接口级服务注册发现到应用级服务注册发现的变化。应用级服务注册发现的机制是同一个应用实例仅在注册中心注册一条数据(以应用名作为唯一key),注册中心只存储应用相关信息(其余信息如:接口数据、接口与应用对应数据存储在配置中心)。

目前我们ABS系统正在做微服务化改造,服务间通讯选择了目前比较活跃的Dubbo3.0。鉴于Dubbo 3.0应用级服务注册发现与之前有很大的变化,而且我们团队也在使用Dubbo3+Nacos2做微服务改造,已积累了一定的实战经验和对Dubbo3.0应用级服务发现有了更深入的了解,本文希望通过接口级服务注册与应用级服务注册对比、应用级服务注册部分核心原理以及Dubbo2.x到3.0升级过程三方面让大家轻松了解Dubbo 3.0应用级服务注册。

注:

接下来以Dubbo3.0.10版本为例,注册中心、元数据中心选用Nacos2.1.0版本给大家做介绍。

2、接口级服务注册与应用级服务注册的区别

上面提到在3.0以前Dubbo虽然在异步化改造、服务治理、三大中心方面做了大量的优化和迭代升级,但是一直是面向接口的服务注册,直到Dubbo3.0发布。Dubbo3.0和Dubbo2.0的区别主要在于接口级服务注册和应用级服务注册的区别,也在于注册中心、元数据中心的使用,如下所示:

 

 

以上是二者与注册中心、元数据中心交互的区别和注册信息的不同。

  • 接口级服务注册:以接口为粒度将接口信息注册到注册中心。信息包括:应用相关信息、接口相关信息、Dubbo相关信息。

  • 应用级服务注册:以应用为粒度将应用信息注册到注册中心。通过3步完成:1.发布接口元数据、2.发布接口与应用映射关系、3.注册应用级服务。

简单来说,接口级服务完成服务注册只需要一步,将接口信息注册到注册中心,而应用级服务需要通过3步完成。下面是具体实例:假设应用annotation-user部署了实例(annotation-user),并且对外提供了 3 个接口(UserApi, TeamApi, UserAuthApi)。在接口级和应用级服务发现机制下,注册到注册中心的数据是截然不同的。如下:

2.1 接口级服务注册

(1)接口级服务注册在注册中心数据:

 

 

 

面向接口的服务注册,应用的每个接口向注册中心进行注册,注册信息包括上面提到的应用相关信息(应用名、应用服务名、服务端口,服务ip)、接口相关信息(接口全路径名、接口方法、接口版本号)、Dubbo相关信息(协议信息、Dubbo版本信息),其中每个接口都有应用相关信息、Dubbo相关信息,而且并没有什么不同,使得接口级服务注册有大量数据冗余。

 

2.2 应用级服务注册

(1)应用级服务注册在注册中心数据

 

通过对比接口级和应用级服务注册在注册中心的数据可以很明显的发现,应用级服务注册的数据以应用为粒度,也就是一个应用只有一条数据,对应元数据信息也少了很多(不涉及接口相关信息),对应用信息和接口信息做了解耦。

 

(2)接口与应用映射关系

 

上面提到注册中心应用服务元数据信息不涉及接口相关信息,所以需要有接口和应用的映射关系,Dubbo3.0通过元数据中心存储接口对应的应用名,这也是应用级服务注册必须要储存的数据。

 

 (3)接口元数据信

 

Dubbo3.0接口元数据相比2.x注册中心的接口信息,接口方法信息更完善,包含:入参出参类型,入参出参类的属性信息等等。

Dubbo2.x、Dubbo3.0默认都会将接口元数据发布到元数据中心,但是服务发现过程并没有用接口元数据,我们可以通过dubbo.registry.use-as-metadata-center: true/false(使用元数据中心)配置决定是否需要将元数据发布到元数据中心(在这里需要注意的是,Dubbo3.0中如果配置dubbo.registry.use-as-metadata-center: false,使得接口应用映射数据无法发布到元数据中心,导致服务订阅方无法获取接口所属的应用而订阅失败,所以应用级服务发现不能关闭元数据中心)。

通过对比我们可以发现,接口级和应用级有以下几点区别:

  1. 接口级服务发现注册中心的每个接口的应用相关信息、Dubbo相关信息没有什么区别,存在大量数据冗余(除了interface、methods之外),而应用级服务注册发现机制注册中心只存储应用相关信息,从而减少注册中心数据存储能力。

  2. 应用级服务发现通过将接口与应用对应关系存储在元数据中心进行应用和接口的解耦,使得注册中心只关注应用相关信息。不需要关注接口的变化,降低了地址变更推送的压力。

  3. 应用级服务注册通过元数据中心存储接口元数据信息、接口应用映射数据,单独维护降低注册中心的压力的同时也导致了应用级服务注册的整个链路、逻辑变得复杂化,给研发和运维同学带来了了解和学习的成本。

3、应用级服务注册部分核心原理

应用级服务注册部分核心原理主要包含3方面:

  1. 接口元数据发布

  1. 接口应用映射数据发布

  1. 应用级服务注册

3.1 接口元数据发布

元数据分两种类型:

1.应用实例中的元数据信息(protocol、version等相关信息)

2.接口相关的元数据信息(接口、方法、host、port、version等等相关信息)

接口元数据发布逻辑相对简单,以下是接口元数据发布到元数据中心的核心调用链路:

 

完成接口元数据发布主要有三步:

  • 接口元数据初始化:元数据初始化工作在服务启动时进行,同时根据Dubbo接口进行初始化并且进行封装。

  • 根据接口信息、Dubbo属性配置生成元数据:在元数据发布阶段从本地获取已初始化的接口信息,拼接生成dataId,生成要发布的元数据json字符串data等。

  • 根据Dubbo配置往元数据中心发布数据:最后封装接口元数据信息,异步发布。

发布的接口元数据信息如下:

 

元数据中心数据格式如下:

 

 

3.2 接口应用映射数据发布

上面接口级服务和应用级服务区别中已经讲到,应用级服务注册发现解耦了应用信息和接口元数据信息(应用信息注册到注册中心,接口元数据信息存储到元数据中心),所以需要接口和应用有一个映射关系,将接口和应用关联起来(此处的接口应用映射数据存储在元数据中心)。

服务导出前期阶段已经完成服务初始化,接口应用映射数据发布过程相对而言比较简单,以下是接口应用映射数据发布核心调用链路:

 

 

完成接口应用映射数据发布主要有2步:

  • 从元数据中心获取已发布的映射数据:如果元数据中心的数据和此时发布的数据一致,则此次不发布数据,如果不一致将原数据和新数据拼接一起发布。 

    注:一个接口可以发布到不同的应用中。

  • 往元数据中心发布接口映射应用数据:拼接dataId,获取默认group=mapping(无法自定义),发布数据信息。

发布的接口应用映射数据信息如下:

 

 

元数据中心数据:

 

 

3.3 应用级服务注册到Nacos

注册应用级服务是Dubbo3.0服务导出的核心流程,也就是之前提到的应用级服务发现机制。

相比接口元数据的发布和应用映射接口数据的发布,应用级服务注册放在了最后执行。

 

 

完成应用级服务注册主要有三步:

  • 创建服务实例:封装元数据(优先取dubbo协议对应的port,如果没有dubbo协议,则取MetadataInfo中URLs集合中第一个URL对象的端口号)。

  • 封装元数据:revision(MetadataInfo中取出所有URL的接口名、协议、version、参数信息进行md5,得到revision,服务相关信息变化表示应用的变化),设置元数据配置dubbo.metadata.storage-type: local/remote,如果local:存储在注册中心应用信息中,remote:存储在元数据中心。

  • 应用级服务注册:最后发布应用服务信息到注册中心。

注:

如果dubbo.metadata.storage-type: remote,将应用元数据发布到元数据中心,否则元数据信息伴随应用信息存储到注册中心。

Dubbo应用group默认为:DEFAULT_GROUP

发布应用信息如下:

 

 

应用级服务在注册中心数据如下:

 

 

 

4. Dubbo2.x到3.0升级过程

根据Dubbo官网资料,3.0版本兼容老版本(2.5、2.6、2.7),因此,往3.0版本的升级过程将会是完全透明的,无需做任何业务改造(除了为使用3.0的一些新特性的配置项之外),升级3.0后的框架行为将保持与2.x 版本完全一致。所以老版本(2.5、2.6、2.7)升级过程中我们直接将dubbo版本升级到3.0即可。

我们以老版本Dubbo2.7.13升级到新版本Dubbo3.0.10为例(2.7.13、3.0.10中依赖的Spring-Boot版本是2.3.1.RELEASE,我们选择一个较新的版本2.6.10)。

对于我们来说Dubbo2.x到3.0升级过程有2个方面的变化:

  • pom依赖管理变化

  • Dubbo配置信息变化

注:如果是第一次使用Dubbo,直接使用Dubbo3.0对应的pom依赖和配置即可。

 

4.1 依赖管理升级

Dubbo2.7.13 依赖管理:

 

Dubbo3.0.10 依赖管理:

依赖管理升级需要做2步:

  1. spring-boot-dependencies根据自己需要升级到2.6.10,或者不升级。

  1. dubbo-bom从2.7.13升级到3.0.10。


4.2 Dubbo配置升级

以下是以Nacos作为注册中心、元数据中心的Dubbo服务配置

Dubbo2.7.13配置:

 

以上是Dubbo 2.7.13 Dubbo属性配置,其中dubbo.registry.group默认为DEFAULT_GROUP,可以自定义

Dubbo3.0.10配置:

 

 

如上配置中:

 

 

以上是Dubbo3.0.10 Dubbo属性配置,【register-mode、service-discovery.migration】部分是升级到3.0的新增配置,需要注意的是:Dubbo 2.x中dubbo.registry.group可以自定义,但是3.0及以上版本中不能自定义(目前最新的版本3.1.0中也不支持自定义)。

配置升级过程:

只需要添加dubbo.application.register-mode,dubbo.application.service-discovery.migration2个属性即可,详细升级过程在下面讲解。

对于大部分服务注册发现,上面的配置已足够使用,下面的配置可以满足一些特殊的需求,例如:多协议、独立的元数据中心等等。

 

 

Dubbo官网属性配置项手册:https://dubbo.apache.org/zh/docs3-v2/java-sdk/reference-manual/config/properties/ 

 

4.3 具体升级步骤

有两条不同的升级路径:

  • 先以兼容模式升级到3.0版本(无需改造),之后在某些时机按需启用新特性(按需改造)

  • 升级与迁移同步完成,在业务升级到3.0版本的同时,完成改造并启用新特性

例如,想启用3.0新特性应用级服务发现:

  1. Provider在保持其他配置不变的情况下将dubbo.application.register-mode改为all(双注册)

  1. Consumer可以不升级或者在保持其他配置不变的情况下将dubbo.application.service-discovery.migration改为APPLICATION_FIRST(双订阅)

  2. 在确认Provider上所有Consumer全部完成应用级地址迁移后,Provider切到应用级地址单注册。完成升级,在Provider切到应用级地址单注册后Consumer也可以切到应用级地址单订阅。

 

4.4 升级过程详解

(1)Provider开启双注册,保证与2.x版本的兼容性:

通过配置dubbo.application.register-mode改为all的方式,将一个应用或实例升级到3.0版本,升级后的Dubbo实例会默认保证与2.x版本的兼容性,会正常注册2.x格式的地址到注册中心,因此升级后的实例仍会对整个集群仍保持可见状态。同时新的地址发现模型(注册应用级别的地址)也将会自动注册。

 

 

此时对于2.x的消费者实例来说,它们看到的是2.x版本的提供者地址列表。对于3.0的消费者,它具备同时发现 2.x与3.0提供者地址列表的能力。在默认情况下,如果集群中存在可以消费的3.0的地址,将自动消费 3.0的地址,如果不存在新地址则自动消费 2.x 的地址。

 

(2)Consumer开启双订阅,保证与2.x版本的兼容性:

通过配置dubbo.application.service-discovery.migration改为APPLICATION_FIRST开启双订阅模式,让升级到3.0的消费端迁移到应用级别的地址,同时也可以订阅2.x地址。

 

注:对于双订阅的场景,消费端虽然可同时订阅2.x地址与3.0地址,但订阅过程中两份地址是完全隔离的:要么用2.x地址,要么用3.0地址,不存在两份地址混合调用的情况,这个决策过程是在收到第一次地址通知后就完成了的。

 

(3)Provider双注册、Consumer双订阅升级完成之后,Provider切到应用级地址单注册,Consumer也可以切到应用级地址单订阅,至此Provider、Consumer升级完成。

 

以下是Dubbo官网2.x升级至3.0操作指南:

https://dubbo.apache.org/zh/docs3-v2/java-sdk/upgrades-and-compatibility/

 

5. 总结

Dubbo3.0相比2.x有了巨大改进,尤其是通过引入应用级服务注册发现模型,主要体现在以下方面:

  • 通过引入应用级服务注册发现模型,适配云原生时代的基础设施(像 Kubernetes等平台都集成了微服务概念抽象,Dubbo3.0的应用级服务发现是适配各种微服务体系的通用模型)

  • 极大解决了注册中心地址数据的存储与推送压力,相应的Consumer侧的地址计算压力也成数量级下降。

  • 注册中心总体数据量有了明显的下降

通过对Dubbo 2.x和3.0的区别对比以及3.0服务端导出全流程的解析发现,应用级服务注册发现机制的实现相对复杂,Dubbo 3.0的其他新特性除了适配云原生还有:新一代的 Triple 协议、多语言友好、Service Mesh等等,本文主要从"接口级与应用级服务注册对比"、"应用级服务注册部分核心原理"以及"Dubbo2.x到3.0升级过程"三方面带大家了解Dubbo3.0应用级服务注册,希望大家有所收获。