将接口级服务发现迁移到应用级服务发现的指南
**总的来说,3.x 在地址注册与发现方面与 2.x 完全兼容,这意味着用户可以选择将集群中任意数量的应用或机器升级到 3.x,并且在升级过程中依然保持与 2.x 版本的互操作性。** 如果您关心迁移背后的工作原理,请参考 迁移规则细节与工作原理
1 快速升级步骤
只需将 pom.xml 修改为最新版本即可完成升级。如果要迁移到应用级地址,只需要调整开关即可控制 3.x 版本的默认行为。
- 将 Provider 应用升级到最新的 3.x 版本依赖,配置双注册开关
dubbo.application.register-mode=all
(建议通过全局配置中心设置,默认自动开启),完成应用发布。 - 将 Consumer 应用升级到最新的 3.x 版本依赖,配置双订阅开关
dubbo.application.service-discovery.migration=APPLICATION_FIRST
(建议通过全局配置中心设置,默认自动开启),完成应用发布。 - 确认 Provider 上的所有消费者都完成应用级地址迁移后,Provider 切换到应用级地址列表注册。完成升级
以下是迁移过程的详细说明。
2 Provider 端升级过程详解
在不改变任何 Dubbo 配置的情况下,可以将应用或实例升级到 3.x 版本,升级后的 Dubbo 实例会默认保证与 2.x 版本的兼容性,即会正常注册 2.x 格式的地址到注册中心,因此升级后的实例对整个集群依然可见。
同时,新的地址发现模型(注册应用级地址)也会被自动注册。
可以通过 -D 参数指定 Provider 启动时的注册行为
-Ddubbo.application.register-mode=all
# Optional values interface, instance, all, the default is all, that is, both interface-level addresses and application-level addresses are registered
此外,还可以在配置中心修改全局默认行为,控制所有 3.x 实例的注册行为。其中,全局开关的优先级低于 -D 参数。
为了保证平滑迁移,即升级到 3.x 的实例可以同时被 2.x 和 3.x 的 Consumer 实例发现,3.x 实例需要开启双注册;当所有上游 Consumer 都迁移到 3.x 地址模型后,Provider 可以切换到实例模式(只注册应用级地址)。关于如何将 Consumer 升级到 3.x,请参阅下一节。
2.1 双注册带来的资源消耗
双注册势必会给注册中心带来额外的存储压力,但考虑到应用级地址发现模型的数据量在存储方面带来的巨大优势,即使对于一些超大规模的集群用户,新的数据量也不会造成存储问题。一般来说,对于一个普通的集群,数据增长可以控制在之前总数据的 1/100 ~ 1/1000
以一个中等规模的集群为例:2000 个实例,50 个应用(500 个 Dubbo 接口,平均每个应用 10 个接口)。
假设每个接口级 URL 地址的平均大小为 5kb,每个应用级 URL 的平均大小为 0.5kb
旧的接口级地址量:2000 * 500 * 5kb ≈ 4.8G
新的应用级地址量:2000 * 50 * 0.5kb ≈ 48M
双注册后,只增加了 48M 的数据量。
3 Consumer 端升级过程
对于 2.x 的 Consumer 实例,它们会自然地看到 2.x 版本的 Provider 地址列表;
对于 3.x 消费者,它能够发现 2.x 和 3.x 提供者地址列表。默认情况下,如果集群中存在可供消费的 3.x 地址,则会自动消费 3.x 地址,如果没有新地址,则会自动消费 2.x 地址。Dubbo3 提供了一个开关来控制此行为。
dubbo.application.service-discovery.migration=APPLICATION_FIRST
# optional value
# FORCE_INTERFACE, only consume interface-level addresses, if there is no address, an error will be reported, and only subscribe to 2.x addresses
# APPLICATION_FIRST, intelligent decision interface level/application level address, double subscription
# FORCE_APPLICATION, only consume application-level addresses, if there is no address, an error will be reported, and only subscribe to 3.x addresses
dubbo.application.service-discovery.migration
支持通过 -D
和 全局配置中心
进行配置。
接下来,让我们仔细看看如何通过双订阅模式 (APPLICATION_FIRST) 将升级到 3.x 的消费者迁移到应用级地址。在具体开发之前,首先明确消费者位置选择行为:**对于双订阅场景,虽然消费者可以同时持有 2.x 地址和 3.x 地址,但在位置选择过程中,两个地址是完全隔离的,绝对不会出现:要么使用 2.x 地址,要么使用 3.x 地址,不会出现两个地址混合调用的情况,这个决策过程是在收到第一个地址通知后完成的。**
接下来,让我们看一下 APPLICATION_FIRST
策略的具体操作流程。
首先,在全局配置中心 Nacos 中提前配置一个配置项(所有消费者默认都会执行此地址选择策略)
接下来,将消费者升级到 3.x 版本并启动。此时,消费者读取 APPLICATION_FIRST
配置并执行双订阅逻辑(订阅 2.x 接口级地址和 3.x 应用级地址)
至此,升级操作完成,剩下的就是框架内的执行。在调用发生之前,框架会在消费者端进行一次“选址过程”。需要注意的是,这里的选址与之前的 2.x 版本不同。选址过程包括两层筛选
- 首先过滤地址列表 (ClusterInvoker)(接口级地址或应用级地址)
- 然后执行实际的提供者地址 (Invoker) 筛选。
ClusterInvoker 筛选的依据可以通过 MigrationAddressComparator SPI 来定义。目前官方提供了一个简单的地址数量比较策略,即满足 应用级地址数量 == 接口级地址数量
时才会进行迁移。
实际上,FORCE_INTERFACE、APPLICATION_FIRST 和 FORCE_APPLICATION 控制的就是这里 ClusterInvoker 类型的过滤策略
3.1 双订阅带来的资源消耗
双订阅必然会增加消费者的内存消耗,但由于应用级地址发现的地址总数优势,这个过程通常是可以接受的。我们从两个方面来分析它
- 双订阅导致地址推送数据量增加。我们在“双注册资源消耗”一节中介绍了这一点,应用级服务发现带来的注册中心数据量增长非常有限。
- 双订阅带来的消费者端内存增加。需要注意的是,双订阅只存在于启动瞬态,在 ClusterInvoker 选址决策后,其中一个地址会被彻底销毁;对于单个服务来说,启动阶段双订阅带来的内存增长可以控制在原有内存的 30% ~ 40% 左右,之后会下降到单订阅水平。如果切换到应用级地址,则可以实现内存降低 50%。
3.2 消费者端更细粒度的控制
除了全局迁移策略外,Dubbo 在消费者端提供了更细粒度的迁移策略支持。控制单元可以是某个消费者应用,它所消费的服务 A 和服务 B 可以有各自独立的迁移策略。具体方法是在消费者端配置迁移规则
key: demo-consumer
step: APPLICATION_FIRST
applications:
- name: demo-provider
step: FORCE_APPLICATION
services:
- serviceKey: org.apache.dubbo.config.api.DemoService:1.0.0
step: FORCE_INTERFACE
使用这种方式可以实现更细粒度的迁移控制,但当前和后续的改造成本会比较高。除了一些特殊场景,我们不建议开启这种配置方式。(迁移指南) **官方推荐全局开关式的迁移策略,允许消费者实例在启动阶段决定使用哪个可用地址列表。**
4 过渡状态的收敛
为了同时兼容 2.x 版本,升级到 3.x 版本的应用会有一段时间处于双注册状态或双订阅状态。
要解决这个问题,我们还是从 Provider 的角度来看。当所有 Provider 都切换到应用级地址注册后,就不会存在双订阅问题。
4.1 不同的升级策略影响很大
毫无疑问,升级越早越彻底,就能越快摆脱这种情况。想象一下,如果组织内的所有应用都能升级到 3.x 版本,版本收敛就会变得非常简单:Provider 在升级过程中始终保持双注册。所有应用都升级到 3.x 后,就可以调整全局默认行为,使 Provider 变成应用级地址列表注册。这个过程不会给 Consumer 应用带来麻烦,因为它们已经是可以识别应用级地址的 3.x 版本了。
如果无法对整个应用进行升级,或者在很长一段时间内只能升级部分应用,那么不可避免的迁移状态将会持续比较长的时间。在这种情况下,我们能追求的只有尽量保持升级后的应用与其上下游实现版本和功能的收敛。推动某些 Provider 的上游消费者升级到 Dubbo3,这样就可以取消这些 Provider 的双注册。要做到这一点,可能需要一些辅助统计工具的支持。
- 能够分析应用之间的依赖关系,例如某个 Provdier 应用被哪些 Consumer 应用消费,这可以通过 Dubbo 提供的服务元数据上报能力来实现。
- 要了解每个应用当前使用的 dubbo 版本,可以通过扫描或主动上报的方式来实现。