本文是ApacheDubbo的实践案例。感兴趣的朋友可以访问官网了解更多详情,或搜索并关注官方微信公众号,关注ApacheDubbo的最新动态。1背景我们公司从2015年开始使用dubbo作为微服务框架,当社区推出dubbo3时,我们立即跟进并进行了深入研究。我们发现dubbo3的应用/实例级服务注册和发现模式可以在一定程度上解决我们目前注册中心面临的压力,解决稳定性和安全性问题。同时,dubbo3在服务治理方面也进行了升级,向云原生架构看齐,并且dubbo3可以向下兼容dubbo2,这也将降低升级的成本和风险。升级工程分阶段推进,目前仍在进行中。通过这篇文章,我们对公司内部的Dubbo3升级过程和收益进行了深入的总结。2Dubbo3核心功能介绍dubbo社区关于dubbo3的文档资料越来越完善。以下是我们从社区引用的部分内容。2.1下一代云原生服务框架Dubbo3被社区寄予厚望,被视为下一代云原生服务框架。Dubbo3提供的核心特性列表主要包括四个部分。一种新的服务发现模型。应用粒度服务发现,云原生设计,适应基础设施和异构系统;性能和集群可扩展性得到极大提升。三、下一代RPC协议。基于HTTP/2Triple协议,兼容gRPC;网关穿透力强,多语言友好,支持ReactiveStream。统一的流量治理模型。对于云原生的流量治理,SDK、Mesh、VM、Container等统一的治理规则可以支持更丰富的流量治理场景。服务网格。在最新的3.1.0版本中,支持SidecarMesh和ProxylessMesh,提供更多的架构选择,降低迁移和落地成本。首先是性能和资源利用率的提升。根据社区数据,升级Dubbo3应用有望实现单机内存降低50%,对于更大的集群效果会更加明显。Dubbo3从架构上支持百万实例级别的集群水平扩展,依托应用级的服务发现,Triple协议可以大幅提升应用的服务管理效率和吞吐量。其次,Dubbo3使得业务架构的升级变得更加容易和合理,尤其是RPC协议。在2.x版本中,web端、移动端和后端之间的通信必须通过网关代理,完成协议转换和类型映射的工作。dubbo3的Triple协议让这些变得更简单自然;通过流式通信模型满足更多的使用场景。最后,得益于Dubbo3完整的云原生解决方案,Dubbo3的mesh架构可以帮助企业屏蔽底层的云原生基础设施细节,让企业更专注于自己的业务,这也是mesh最根本的优势。2.2应用级服务发现的核心原理我们先从最经典的Dubbo工作原理图说起。Dubbo从设计之初就内置了发现服务地址的能力。提供者向注册中心注册地址,消费者通过订阅获取注册中心地址的实时更新。消费者收到地址列表后,根据特定的负载均衡策略向提供者发起RPC调用。在这个过程中,每个Provider通过特定的密钥向注册中心注册本地可访问的地址;注册中心通过这个key聚合provider实例的地址;消费者通过同一个密钥向注册中心进行订阅,从而及时收到聚合后的地址列表;下面我们看一下Provider向注册中心注册的URL地址的详细格式。这里,URL地址数据分为几部分:首先是实例的可访问地址,主要信息包括ip端口,是消费者会根据数据生成tcp网络链接作为传输载体用于后续的RPC数据。第二个是RPC元数据,用于定义和描述一个RPC请求,表示这段地址数据是与一个特定的RPC服务相关的,它的版本号、分组、方法相关的信息。接下来是RPC配置数据,一部分用于控制RPC调用的行为,一部分用于同步Provider流程实例的状态,典型的如超时时间、数据编码的序列化方式等。最后一部分是自定义元数据。这部分不同于上述框架的预定义配置,给用户更多的灵活性。用户可以任意扩展和添加自定义元数据,进一步丰富实例状态。结合以上对Dubbo2接口级地址模型的分析和最初的Dubbo基本示意图,可以得出几个结论:第一,地址发现聚合的关键是RPC粒度服务。其次,注册中心同步的数据不仅包括地址,还包括各种元数据和配置。得益于1和2,Dubbo实现了支持应用、RPC服务、方法粒度的服务治理能力。这也是为什么Dubbo2在易用性、服务治理功能、扩展性等方面一直强于很多服务框架的真正原因。面对地址量级放大的问题,在Dubbo3架构下,社区认真考虑了两个问题:如何在保留易用性和功能性的情况下重组URL地址数据,避免数据冗余,让Dubbo3能否支持更大的水平扩展集群?地址发现层面如何与其他微服务系统如Kubernetes、SpringCloud等进行对接?最后,社区给出的解决方案也非常巧妙和经典。Dubbo3的应用级服务发现方案的基本设计思路是:地址发现链路上的聚合元素,也就是前面提到的key,从service调整到application,这也是它名字叫application的由来级别的服务发现,类似kubernetes和springCloud的服务注册发现是同粒度的,可以平滑衔接;此外,通过注册中心同步的数据内容也进行了大幅简化,只保留核心ip和端口地址数据。经过上述调整,应用层服务发现在保持接口层地址模型易用性的同时,实现了个体地址数据规模和总数的缩减。元数据、配置数据和自定义数据通过元数据中心或MetadataService同步,并为所有数据生成元数据修订。如果元数据修订相同,则认为元数据和其他信息相同。这样,MetadataService的元数据中心或访问频率。3前期研究在了解了Dubbo3的核心功能和应用级服务发现的工作原理之后,我们开始进入前期工作阶段。3.1性能压力测试从社区的资料来看,dubbo3各方面都非常好,但是我们自己去查,所以我们使用的是目前内部定制的dubbo2版本和dubbo3的性能压力测试。压测的主要场景是同步调用和异步场景,只做了dubbo3的压测。以下压力测试数据和结论仅供参考。结果表明,dubbo3在性能方面确实做了很多优化。在cpu占用率相同的情况下,dubbo3的tps高于dubbo2;在tps相同的情况下,dubbo3的cpu使用率低于dubbo2。尤其是dubbo2的interface级别和dubbo3的instance级别,在tps相同的情况下,dubbo3的cpu使用率比dubbo2的定制版低20%左右。压测环境:类别版本机器配置Providerdubbo3.0.44C8GConsumerdubbo3.0.44C8GProviderdubbo2.5.3.22(基于2.5.3版本定制)4C8GConsumerdubbo2.5.3.222(基于2.5.3版本定制)4C8G测试场景:使用Dubbo协议,接口不做其他逻辑,输入直接返回给消费者,接口数据包大小500B,每个场景压30分钟。测试数据(仅供参考):3.2升级前调研并做压测在得到dubbo2和dubbo3的压测数据后,我们开始计划将dubbo3引入公司进行试点。这个时候就需要考虑dubbo3和dubbo2的兼容和迁移的结构问题,升级目标,dubbo3提供了哪些能力来支持升级和迁移。3.2.1升级兼容性和迁移重构考虑到公司的系统规模,dubbo2升级到dubbo3并不是一个容易的过程,尤其是公司的dubbo2版本在原有开源版本的基础上做了很多的优化和扩展,涵盖ops服务治理、monitor数据指标监控、服务注册与发现、RPC灰度路由、链接分析、序列化编解码等诸多方面,作为其他基础框架的底层支持,dubbo3社区也很活跃,我们也希望继续享受dubbo社区的技术红利。在此背景下,我们不得不考虑三个问题:公司版dubbo2与dubbo3的兼容性需要解决;原有功能的迁移和重构;对源代码进行更改以使其与社区版本保持一致。得益于dubbo良好的扩展性,我们可以在dubbo3的基础上使用dubbo的SPI和IoC模块优雅的兼容公司版本的dubbo2,无需更改dubbo3的源码,只要开发好dubbo3的扩展包,后面跟着dubbo3版本的API升级,相比于从社区获得红利,这种升级变化的成本是比较小的。3.2.2升级目标既然解决了历史包袱,就该考虑升级的目标了。首先要确定的是,我们最终会采用实例级的服务注册和服务发现。其次,我们目前使用的注册中心是zookeeper,dubbo社区推荐的注册中心是nacos,我们在验证阶段也暴露了。几个在zookeeper上出现而nacos上没有出现的问题,也让我们考虑以后是否将注册中心迁移到nacos上。同时,我们也希望整个迁移过程是顺畅可控的。我们的整体方案也要以风险控制为核心点,尽可能做到故障降级和实时可控。综上所述,我们将升级目标总结为以下几点:1)从dubbo2顺利升级到dubbo3。2)将接口级服务注册和发现模式平滑迁移到应用级服务注册和发现模式。3)为后面注册中心的顺利迁移做准备。4)迁移过程可以被监控和观察。5)迁移过程应是灰度化的、实时可控的。6)统一dubbo3的通用配置规范,尽量适配原有dubbo2的export和refer方式。3.2.3dubbo3支持迁移的能力前面的介绍是我们的目标,但是如何将dubbo3原有的设计理念融入到实际情况中呢?以下是我们的相关思考,并在验证过程中。首先,dubbo3可以通过registryUrl上的参数管理provider和consumer来支持不同模式下的服务注册和服务发现,其中核心参数名称为:registry-type、registry-protocol-type、register-mode。其次,dubbo3可以支持使用多个注册中心,不同的注册中心通过上面的registryUrl参数控制注册中心的服务注册方式和服务发现方式。而且,Provider端和Consumer端使用的注册中心可以分别通过ProviderConfig和ConsumerConfig这两个Config类进行管理。在consumer端,如果使用多个registry,默认会使用ZoneAwareCluster创建的ZoneAwareClusterInvoker进行负载均衡。从类名可以看出,ClusterInvoker具有提供区域感知的能力。在查看源码的时候,发现它也提供了preferred的功能,只需要在对应的registryUrl中加上preferred=true,就会优先调用这个registryUrl创建的ClusterInvoker。在接口级别迁移到同一个注册中心的实例级别的场景下,dubbo3的MigrationInvoker也提供了相应的支持。MigrationInvoker可以根据MigrationRule对实例级别的RPC流量进行控制,并可以根据MigrationRuleListener实时监听指定应用的MigrationRule的变化。关于RPC监控,MonitorFilter和DubboMonitor一直在dubbo中提供RPC监控数据采集和上报。采集的数据包括消费者ip端口,提供者ip端口,应用名称,DubboService,Method,以及成功失败次数,输入字节数,输出字节数,耗时,并发等,这些能力可以满足基本迁移工作。以我们目前的情况来看,相对于升级目标要求的平滑迁移,迁移流量可以观察,可以灰度,还有一定的距离可控,但是在梳理dubbo3的能力的时候,我也发现了一个比较简单的扩展计划。至此,整体的迁移方案也有了一个大概的雏形。4升级迁移方案本设计方案的设计重点是“平滑可控”。根据dubbo3的新架构,目前正在验证的迁移方案示意图如下:从上图可以看出,在整个升级迁移过程中,应用域中会存在多个dubbo版本.dubbo3是兼容社区的dubbo2版本,我们公司内部的dubbo2版本是在dubbo2.5.3开源版本的基础上深度定制的。在ops服务管理、monitor数据指标监控、Service注册与发现、RPC灰度路由、序列??化编解码等方面进行了扩展和定制。我们的思路是使用dubbo3基于dubbo的SPI来使用extended方法或者ExtensionLoader的Wrapper方式来兼容dubbo2的定制版本。除了应用之外,在dubbo3架构的基础上还划分了3个逻辑域,分别是注册域、配置控制域和监控域。注册域主要服务于服务的注册和发现。例如,当DubboService暴露后,提供者向注册域的注册中心和元数据中心上报服务信息和元数据信息,消费者通过注册中心和元数据中心发现服务。配置控制域主要是管理应用配置和迁移流量控制。dubbo3提供的配置中心支持自身能力的配置,所以流量规则的配置由dubbo3的配置中心维护。dubbo3的DynamicConfigration提供了很多动态配置的方法。使用。监控域除了对原有RPC流量的监控外,还细分了对迁移流量的监控。在迁移过程中,通过监控可以直观的看到迁移流量的状态。当出现问题时,可报警通知相关人员及时介入。整个升级过程分为3个阶段:Stage1:将dubbo2升级到dubbo3的接口层,验证功能、兼容性、性能和稳定性Stage2:接口层和应用层双注册,通过MigrationRule和RegistryMigrationRule管理RPC的第三阶段流量:全面切换到应用层,去掉MigrationRule和RegistryMigrationRule4.1dubbo3扩展兼容dubbo2定制版考虑到dubbo3社区版的迭代,最终决定dubbo3兼容dubbo2定制版。兼容的扩展功能主要包括以下内容:RPC正向透传和反向透传分别在消费者端和提供者端扩展Filter接口实现类,实现正向和反向透传数据的发送和接收功能。Dubbo2定制版在序列化编解码级别修改了RpcResult。为了兼容这个逻辑,只能在序列化编解码级别支持。Wrapper模式用于增强Codec2的SPI,与其他扩展类一起实现。兼容功能。RPC灰度路由扩展了Dubbo的Router、Cluster、ConfiguratorFactorySPI,并与内部eunomia灰度管控平台集成,实现RPC灰度路由。替代并兼容原dubbo2定制版的灰度路由功能,在其源码层面进行了修改。Monitor数据指标监控扩展Protocol、MonitorFilter、Monitor等SPI,完成与内部监控中心的对接,与dubbo2定制版的监控逻辑一致。ops支持实例级别。在ops层面,除了兼容原有的接口级服务控制外,还必须增加实例级服务控制。其他中间件的兼容性除了dubbo本身的兼容性之外,还有一些自研的中间件依赖于dubbo或者与dubbo相关,这些中间件需要进行改造升级。4.2迁移与扩展在dubbo3原有能力的基础上,进行额外的扩展,提供平滑的迁移能力。我们设想的设计方案如下:扩展支持注册中心的迁移,可以在dubbo3中灰显控制。当应用在消费者端创建多个注册中心时,ZoneAwareCluster会默认创建ZoneAwareClusterInvoker用于负载均衡。参考其实现扩展一个Cluster实现类和一个ClusterInvoker实现类来替代ZoneAwareCluster,以及registry迁移的流量管理、灰度、降级能力。都在扩展的ClusterInvoker中实现,实现支持接口级到实例级迁移规则的全局配置管理。MigrationRule使用MigrationRuleListener通过DynamicConfiguration监听指定应用的迁移规则。如果采用这种方式进行管理,维护成本会变高。我们借鉴了这种方法,实现了全局级别的MigrationRule管理能力。扩展迁移流量可以观察告警DubboRPC流量监控已经通过MonitorFilter和DubboMonitor实现,但是MonitorFilter无法识别本次RPC请求的Invoker对象使用哪个注册中心进行服务发现,以及Invoke对象的服务发现方式是不是在接口级别或实例级别;我们在消费者端添加一个ClusterFilter接口和一个Filter接口来实现这个识别逻辑。迁移组件切换在扩容结束的时候,需要考虑迁移组件下线的问题。即使下线了,也不可能再次调整业务项目,将依赖项中的迁移组件全部删除。因此,需要通过开关对迁移组件的功能进行离线控制。4.3配置统一管理在升级迁移过程中,我们可能随时调整注册中心的配置参数和迁移规则。为了减少出错的风险和业务工程升级变更的工作量,需要对这些公共配置进行统一的管理和维护。dubbo3通常情况下,配置中心可以更好地承担这个任务。最后我们扩展了一个配置加载组件,通过我们公司内部的配置中心来管理和维护迁移组件的开关和配置中心的连接地址和超时时间等配置参数。有了这个组件,新的应用就不用担心dubbo3的公共配置和迁移,老应用也减少了调整这部分公共配置的工作量。4.4风险预案作为一个提供底层支撑能力的微服务框架,dubbo始终把稳定性的需求放在首位。升级过程中的任何意外都可能导致线上问题,所以我们的整个计划都是以失败为导向,为风险而设计的。除了在扩展迁移组件中实现主动降级外,还考虑了一些极端情况,并针对这些极端情况提供了风险预案。在线环境中可能会发生各种意外情况。在迁移过程中,需要提前考虑各种风险,制定完善的应对预案,确保系统快速恢复。4.5小结dubbo2是一个优秀的微服务框架。提供的SPI和Extension机制可以非常方便的让用户扩展实现自己想要的功能。dubbo3在其基础上丰富了很多新的SPI。我们花了很长时间设计迁移方案,真正开发迁移组件的时间比较短。dubbo3整体架构的升级调整,也解决了以往服务注册的压力。性能也进行了优化,升级后的dubbo3更适合现在的云原生架构。dubbo3.1.x版本支持sidecar和proxylessmesh方案,社区也在准备开源的javaagentproxyless,这样可以比较好的将微服务框架的框架与数据面解耦,减少维护成本和微服务框架的升级成本。5社区协作目前,项目还在持续升级中。我们与社区保持密切联系。这期间,我们遇到了很多问题,社区发展同学耐心解答,最终解决。对于想要升级Dubbo3的用户,可以在社区的GithubUserIssue(https://github.com/apache/dub...)注册。想参与社区的同学也可以关注Dubbo官方公众号(搜索ApacheDubbo)了解更多dubbo社区的进展。搜索并关注官方微信公众号:ApacheDubbo,了解更多行业最新动态,掌握各大厂面试必备的Dubbo技能
