平安健康 Dubbo 3 升级、迁移和验证之路

作者:李斌、邱炜

背景

我们公司从 2015 年开始就使⽤ Dubbo 作为微服务框架,当社区推出 Dubbo 3 时,我们也⽴刻跟进并做了深⼊调研,发现 Dubbo 3 的应⽤/实例级服务注册和发现模式能够在一定程度上解决我们当前注册中⼼⾯临的压⼒,解决稳定性和安全性问题。同时 Dubbo 3 在服务治理上也做了升级,契合云原⽣架构,⽽且 Dubbo 3 能够向下兼容 Dubbo 2,这也将降低升级的成本和⻛险。

升级项目有了阶段性的进展,目前仍然在进行中。通过本⽂,我们对公司内部的 Dubbo 3 升级过程及收益等做了深⼊总结。

社区关于 Dubbo 3 的核心功能介绍

Dubbo 社区关于 Dubbo 3 的文档和资料越来越完善,以下是我们从社区引用的一些内容。

下一代云原生服务框架

1.png

Dubbo 3 被社区寄予厚望,将其视为下一代云原生服务框架打造,Dubbo 3 提供的核心特性列表,主要包括四部分。

  1. 全新服务发现模型。应用粒度服务发现,面向云原生设计,适配基础设施与异构系统;性能与集群伸缩性大幅提升。

  2. 下一代 RPC 协议 Triple。基于 HTTP/2 的 Triple 协议,兼容 gRPC;网关穿透性强、多语言友好、支持 Reactive Stream。

  3. 统一流量治理模型。面向云原生流量治理,SDK、Mesh、VM、Container 等统一治理规则;能够支持更丰富的流量治理场景。

  4. Service Mesh。在最新的3.1.0的版本中支持Sidecar Mesh 与 Proxyless Mesh,提供更多架构选择,降低迁移、落地成本。

2.png

首先是性能、资源利用率的提升。社区资料显示,升级 Dubbo 3 的应用预期能实现单机内存 50% 的下降,对于越大规模的集群效果将越明显,Dubbo 3 从架构上支持百万实例级别的集群横向扩展,同时依赖应用级服务发现、Triple 协议等可以大大提供应用的服务治理效率和吞吐量。

其次,Dubbo 3 让业务架构升级变得更容易、更合理,尤其是 RPC 协议,在 2.x 版本中,web、移动端与后端的通信都要经过网关代理,完成协议转换、类型映射等工作,Dubbo 3 的 Triple 协议让这些变得更容易与自然;并通过流式通信模型满足更多的使用场景。

最后,得益于 Dubbo 3 的完善云原生解决方案,Dubbo 3 的 Mesh 架构可以帮助业务屏蔽底层云原生基础设施细节,让业务更专注于业务,这也是 Mesh 的最根本的优势。

应用级服务发现核心原理

3.png

我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,Consumer 基于特定的负载均衡策略发起对 Provider 的 RPC 调用。

在这个过程中:

  1. 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址;
  2. 注册中心通过这个 key 对 Provider 实例地址进行聚合;
  3. Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表;

4.png

再来看一下 Provider 向注册中心注册的 URL 地址的详细格式,这里把 URL 地址数据划分成了几份:

  1. 首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体。
  2. 其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息。
  3. 下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。
  4. 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。

结合以上对于 Dubbo 2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,可以得出这么几条结论:

  1. 地址发现聚合的 key 就是 RPC 粒度的服务。
  2. 注册中心同步的数据不止包含地址,还包含了各种元数据以及配置。
  3. 得益于 1 与 2 ,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力。

这就是一直以来 Dubbo 2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。

面对这样的地址数量级放大的问题,在 Dubbo 3 架构下,社区认真思考了两个问题:

  1. 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo 3 能支撑更大规模集群水平扩容?
  2. 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通?

5.png

最终,社区给出的方案也是非常巧妙和经典。Dubbo 3  的应用级服务发现方案设计的基本思路是:地址发现链路上的聚合元素也就是之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来,与 Kubernetes 和 Spring Cloud 的服务注册发现处于同一粒度,能够平滑打通;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。经过上述调整,应用级别服务发现在保持接口级地址模型易用性的同时,实现了地址单条数据大小和总数量的下降。

元数据、配置数据以及自定义数据等通过元数据中心或者 MetadataService 进行同步,且将所有的数据生成一个 Metadata Revision,如果 Metadata Revision 相同则认为元数据等信息相同,通过这种方式来降低元数据中心或 MetadataService 的访问频次。

前期调研

了解了 Dubbo 3 的核心功能以及应用级服务发现的工作原理后,我们开始进入前期工作阶段。

性能压测

从社区的资料来看,Dubbo 3 各方面都非常不错,但是我们还得自己检验一次,所以我们使用当前在用的 Dubbo 2 内部定制版和 Dubbo 3 的性能压测,压测的主要场景在于同步调用,异步场景只做了 Dubbo 3 的压测,以下压测数据和结论仅供参考

结果表明 Dubbo 3 在性能上面确实做了很多的优化,在相同 CPU 使用率的情况下,Dubbo 3 的 TPS 是要高于 Dubbo 2 的;TPS 相当的情况下,Dubbo 3 的 CPU 使用率要低于 Dubbo 2 。尤其是 Dubbo 2 的接口级与 Dubbo 3 的实例级,在 TPS 相当的情况下, Dubbo 3 的 CPU 使用率要较定制版的 Dubbo 2 低 20% 左右。

压测环境:

类别 版本 机器配置
Provider Dubbo 3.0.4 4C8G
Consumer Dubbo 3.0.4 4C8G
Provider Dubbo 2.5.3.22 (基于 2.5.3 版本定制) 4C8G
Consumer Dubbo 2.5.3.22 (基于 2.5.3 版本定制) 4C8G

测试场景:

使用的是 Dubbo 协议,接口没有其它逻辑,直接将输入返回给消费者,接口数据包大小 500B ,每个场景压 30 分钟。

测试数据 (仅供参考):

6.png

升级前调研

做了压测得到 Dubbo 2 和 Dubbo 3 的压测数据后,我们开始计划将 Dubbo 3 引入公司进行试点,此时,我们需要考虑 Dubbo 3 与 Dubbo 2 的兼容和迁移重构问题,升级目标,以及 Dubbo 3 提供有哪些能力支持升级和迁移。

  • 升级的兼容和迁移重构问题

考虑到公司的系统规模,要将 Dubbo 2 升级到 Dubbo 3 却不是一个简单的过程,尤其是公司的 Dubbo 2 版本在原开源版本基础之上做了不少优化和扩展,涵盖了 OPS 服务治理、Monitor 数据指标监控、服务注册和发现、RPC 灰度路由、链路分析、序列化编解码、作为其他基础框架的底层支持等多个方面。同时 Dubbo 3 社区也处于活跃的状态,我们也希望能够持续享受 Dubbo 社区的技术红利,在这样的背景下不得不考虑三个问题:

  1. 需要解决公司版本的 Dubbo 2 与 Dubbo 3 的兼容问题
  2. 原有功能的迁移重构问题
  3. 不在 Dubbo 3 的源码上做改动,保持和社区版本一致

得益于 Dubbo 良好的扩展能力,我们可以通过 Dubbo 的 SPI 和 IoC 模块在 Dubbo 3 的基础之上优雅的兼容公司版本的 Dubbo 2 ,不用改动 Dubbo 3 源码,只要研发 Dubbo 3 扩展包跟随 Dubbo 3 版本的 API 升级即可,这个升级改动的成本和从社区获取红利相比是比较小的。

  • 升级目标

既然历史包袱的解决方案已经有了,那么就要思考升级的目标了。首先确定的是,最终我们将会采用实例级的服务注册和服务发现,其次我们目前使用的注册中心是 Zookeeper,而 Dubbo 社区更推荐使用的注册中心是 Nacos,而且我们在验证阶段时也暴露过几个在 Zookeeper 上出现而在 Nacos 上没有出现的问题,这也使得我们开始考虑将来是否将注册中心最终也迁移到 Nacos 上。

同时,我们也希望整个迁移过程是平滑、可控的,我们整体方案也要将风险把控作为核心要点考虑,尽可能的做到失败降级、实时可控。

综上,我们将升级的目标归纳为下面几点:

  1. 平滑的从 Dubbo 2 升级到 Dubbo 3
  2. 将接口级服务注册和发现模式平滑的迁移到应用级服务注册和发现模式为
  3. 后面平滑迁移注册中心做好准备
  4. 迁移过程可监控、可观测。
  5. 迁移过程要可灰度、可实时管控
  6. 统一 Dubbo 3 的通用配置规范,尽量适配原 Dubbo 2 的 Export 和 Refer 方式。
  • Dubbo 3 对于迁移的支撑能力

前面介绍的是我们的目标,但是如何把 Dubbo 3 的原生设计理念融入到现实情况中呢?以下是我们的相关思考,并在验证过程中。

首先 Dubbo 3 能够支持在 RegistryUrl 上通过参数管理 Provider 和 Consumer 以不同的模式进行服务注册和服务发现,其中核心参数名有: registry-type, registry-protocol-type, register-mode。

其次,Dubbo 3 可以支持使用多个注册中心,不同的注册中心通过上面的 RegistryUrl 参数控制注册中心的服务注册模式和服务发现模式。而且还可以通过 ProviderConfig 和 ConsumerConfig 这两个这两个 Config 类分别管理 Provider 侧和 Consumer 侧使用的注册中心。在 Consumer 侧,如果有使用多个注册中心,默认会使用 ZoneAwareCluster 创建的 ZoneAwareClusterInvoker 来进行负载均衡,从类名上可以看出,该 ClusterInvoker 是有提供区域感知的能力,查看源码时发现它还提供了 preferred 的功能,只在相应的 registryUrl 中添加了 preferred=true,这个registryUrl 创建的 ClusterInvoker 就会被优先调用。

在同一注册中心进行接口级迁移到实例级的场景中, Dubbo 3 的 MigrationInvoker 也提供了相应的支持,MigrationInvoker 可以根据 MigrationRule 来控制实例级的 RPC 流量,并且根据 MigrationRuleListener 能够实时监听到指定应用的 MigrationRule 的变更。

关于 RPC 的监控在 Dubbo 中一直由 MonitorFilter 和 DubboMonitor 提供 RPC 监控数据的收集和上报,收集的数据有消费者的 ip 端口、提供者的 ip 端口、应用名称、DubboService、Method、以及成功数、失败数、输入字节数、输出字节数、耗时、并发数等。

这些能力能够满足基本的迁移工作,结合我们的现状来看,相对升级目标要求的平滑迁移,迁移流量可观测、可灰度、可管控还有一些距离,不过在梳理 Dubbo 3 这块能力的时候,也找到了相对简单的扩展方案。到此,对于整体的迁移方案也有了一个大致的雏形。

升级&迁移方案设计

方案的设计重点放在 “平滑、可控” 两点,根据 Dubbo 3 的新架构,目前正在验证中的迁移方案示意图如下:

7.png

从上图可以看出,在整个升级迁移的过程中,应用域中会存在多个 Dubbo 版本,Dubbo 3 是能够兼容社区的 Dubbo 2 版本,而我们公司内部的 Dubbo 2 版本是基于 Dubbo 2.5.3 开源版本深度定制过的,在 OPS 服务治理、Monitor 数据指标监控、服务注册和发现、 RPC 灰度路由、序列化编解码等方面都做了扩展定制,我们的思路是由 Dubbo 3 基于 Dubbo 的 SPI 采用扩展的方式或者 ExtensionLoader 的 Wrapper 模式去兼容定制版的 Dubbo2。

除了应用外,在 Dubbo 3 的架构基础上划分了 3 个逻辑域,分别是注册域、配置管控域和监控域。

注册域主要服务于服务的注册和发现,例如 Provider 在 DubboService 暴露时,将服务信息和元数据信息上报到注册域的注册中心和元数据中心,Consumer 通过注册中心和元数据中心来发现服务。配置管控域主要是管理应用配置和迁移流量管控,Dubbo 3 提供的配置中心支持自身能力的配置,所以流量规则的配置由Dubbo 3 的配置中心进行维护,Dubbo 3 的 DynamicConfigration 提供了很多关于动态配置的方法可以直接使用。监控域除了原 RPC 流量的监控外,还细分了迁移流量的监控,在迁移过程中,可以通过监控直观的看到迁移流量的现状,出现问题时,也可以及时报警通知相关人员介入。

整个升级过程分为 3 个阶段:

  • 第一阶段:将 Dubbo 2 升级到 Dubbo 3 的接口级,验证功能、兼容性、性能和稳定性
  • 第二阶段:接口级和应用级双注册,通过 MigrationRule 和 RegistryMigrationRule 管理RPC流量
  • 第三阶段:全面切换到应用级,撤掉MigrationRule 和 RegistryMigrationRule

Dubbo 3 扩展兼容 Dubbo 2 定制版本

考虑到 Dubbo 3 社区版本的迭代情况,最终决定 Dubbo 3 兼容 Dubbo 2 定制版本的插件以 SDK 的方式单独维护,实现兼容的扩展功能主要有如下内容:

  1. RPC 正向透递与反向透传

在 Consumer 侧和 Provider 侧扩展 Filter 接口实现类,为正向与反向透传数据实现其发送和接收的功能。Dubbo 2 定制版是在序列化编解码层面对 RpcResult 进行了修改,要兼容这一逻辑也只能在序列化编解码层面去支持,采用 Wrapper 模式对 Codec2 这个 SPI 进行增强,与其它扩展类一并实现该兼容功能。

  1. RPC 灰度路由

扩展 Dubbo 的 Router、 Cluster 和ConfiguratorFactory 等 SPI,与内部的 eunomia 灰度管控平台集成实现 RPC 灰度路由,替换并兼容掉原 Dubbo 2 定制版在其源码层面修改实现的灰度路由功能。

  1. Monitor数据指标监控

扩展 Protocol、MonitorFilter、Monitor 等 SPI,与内部的监控中心完成对接,与 Dubbo 2 定制版的监控逻辑保持一致。

  1. OPS 支持实例级

在 OPS 层面,除了要兼容原接口级的服务管控外,还要添加实例级的服务管控。

  1. 其它中间件兼容

除了 Dubbo 本身的兼容外,内部还有部分自研的中间件也是有依赖 Dubbo 或者跟 Dubbo 有关联的,还要对这些中间件进行改造升级。

迁移扩展

在 Dubbo 3 原有能力基础上,也要另外进行扩展以提供平滑迁移的能力,我们构想的设计方案如下:

  1. 扩展支持注册中心的迁移可灰度、可管控

在 Dubbo 3 中,当 Consumer 侧应用了多个注册中心时,默认会通过 ZoneAwareCluster 创建 ZoneAwareClusterInvoker 来进行负载均衡,参考其实现可以扩展一个 Cluster 实现类和一个 ClusterInvoker 实现类将 ZoneAwareCluster 替换掉,注册中心迁移的流量管理、灰度、降级等能力都在扩展的 ClusterInvoker  中去实现。

  1. 扩展支持接口级到实例级迁移规则的全局配置管理

MigrationRule 由 MigrationRuleListener 通过 DynamicConfiguration 监听指定的应用的迁移规则,如果一个系统拥有成百上千个微服务应用时,由这种方式去管理,维护成本将会变高,我们借鉴这个方法实现了全局级别的 MigrationRule 管理能力。

  1. 扩展迁移流量可观测、可报警

Dubbo RPC 的流量监控已经有 MonitorFilter 和 DubboMonitor 实现了,只是 MonitorFilter 不能识别本次 RPC 请求的 Invoker 对象是通过哪个注册中心进行服务发现的,以及该 Invoke 对象的服务发现模式是接口级还是实例级的;我们在 Consumer 侧新增一个 ClusterFilter 接口和 Filter 接口去实现这个识别逻辑。

  1. 迁移组件开关

在扩展的最后,要考虑迁移组件下线的问题,即使要下线也不可能再次调整业务工程将迁移组件全部从依赖中删除掉,所以需要通过开关控制迁移组件的功能下线。

配置统一管理

在升级和迁移过程中,我们可能会随时调整注册中心和迁移规则的配置参数,为减少出错的风险以及业务工程升级改动的工作量,这些公共的配置需要统一管理维护起来,Dubbo 3 的配置中心正常能够把这个任务较好的承接下来。

最终我们又扩展了一个配置加载的组件,通过我们公司内部的配置中心管理维护迁移组件的开关和配置中心的连接地址与超时等配置参数。有了这个组件后,新的应用可以不用担心 Dubbo 3 和迁移的公共配置,老的应用也减少了这部分公共配置的调整工作量。

风险预案

Dubbo 作为一个提供底层支撑能力的微服务框架,我们始终把稳定性的要求放在首位,升级过程中任何一点意外,都可能导致线上问题,所以我们整个方案都是在面向失败、面向风险设计的。除了在扩展的迁移组件中实现了主动降级外,也着重考虑了一些极端情况,同时为这些极端情况提供风险预案。线上环境可能会出现各种意想不到的情况,在迁移过程中需要预先思考各种风险,准备完善的应对处理预案,保证系统快速恢复。

小结

Dubbo 2 是一个优秀的微服务框架,提供的 SPI 以及 Extension 机制能够非常方便的让用户去扩展实现想要功能。Dubbo 3 在其基础之上,丰富了不少新的 SPI ,我们花了很长的时间去设计迁移方案,真正花在迁移组件上的开发时间较短。

Dubbo 3 整体架构升级调整对于过去的服务注册压力也得到了解决。性能上也做了优化,架构升级后的 Dubbo 3 也更适应目前云原生的架构,Dubbo 3.1.x 版本支持 Sidecar 和 Proxyless 的 Mesh 方案,而且社区也在准备开源 Java Agent 方式的 Proxyless,这样就能较好的将微服务架框的 Framework 与数据面解耦,降低微服务框架的维护成本和升级成本。

社区协作

目前该项目仍然在持续升级中,我们跟社区保持着紧密的联系,期间碰到不少问题,都得到了社区开发同学耐⼼解答并最终给予解决。

对于要升级 Dubbo3 的⽤户,可以在社区的 Github  置顶  Issue 进⾏登记。

posted @ 2023-01-11 14:55  阿里巴巴中间件  阅读(92)  评论(0编辑  收藏  举报