Dubbo2.x迁移3.x过程及原理

Dubbo2.x迁移3.x过程及原理

  • 1.Dubbo2.x迁移3.x
    • 1.1 快速升级步骤
    • 1.2 Provider 端升级过程详解
      • 1.2.1 双注册带来的资源消耗
    • 1.3 Consumer 端升级过程
      • 1.3.1 APPLICATION_FIRST策略
      • 1.3.2 双订阅带来的资源消耗
      • 1.3.3 消费端更细粒度的控制
    • 1.4 迁移状态的收敛
      • 1.4.1 不同的升级策略影响很大
  • 2. 迁移规则说明
    • 2.1 状态模型
    • 2.2 规则体说明
    • 2.3 配置方式说明
      • 2.3.1. 配置中心配置文件下发(推荐)
      • 2.3.2 启动参数配置
      • 2.3.3 本地文件配置
    • 2.4 决策说明
      • 2.4.1 阈值探测
      • 2.4.2 灰度比例
    • 2.5 切换过程说明
      • 2.5.1 切换到应用级优先
      • 2.5.2 应用级优先切换到强制
      • 2.5.3 强制接口级和强制应用级互相切换

前言
Dubbo3 依旧保持了 2.x 的经典架构,以解决微服务进程间通信为主要职责,通过丰富的服务治理(如地址发现、流量管理等)能力来更好的管控微服务集群;Dubbo3 对原有框架的升级是全面的,体现在核心 Dubbo 特性的几乎每个环节,通过升级实现了稳定性、性能、伸缩性、易用性的全面提升。
在这里插入图片描述

1.Dubbo2.x迁移3.x

1.1 快速升级步骤

简单的修改 pom.xml 到最新版本就可以完成升级,如果要迁移到应用级地址,只需要调整开关控制 3.x 版本的默认行为。

  • 升级 Provider 应用到最新 3.x 版本依赖,配置双注册开关dubbo.application.register-mode=all(建议通过全局配置中心设置,默认已自动开启),完成应用发布。
  • 升级 Consumer 应用到最新 3.x 版本依赖,配置双订阅开关dubbo.application.service-discovery.migration=APPLICATION_FIRST(建议通过全局配置中心设置,默认已自动开启),完成应用发布。
  • 在确认 Provider 的上有 Consumer 全部完成应用级地址迁移后,Provider 切到应用级地址单注册。完成升级

1.2 Provider 端升级过程详解

在不改变任何 Dubbo 配置的情况下,可以将一个应用或实例升级到 3.x 版本,升级后的 Dubbo 实例会默保保证与 2.x 版本的兼容性,即会正常注册 2.x 格式的地址到注册中心,因此升级后的实例仍会对整个集群仍保持可见状态。

同时新的地址发现模型(注册应用级别的地址)也将会自动注册。
在这里插入图片描述

通过 -D 参数,可以指定 provider 启动时的注册行为

-Ddubbo.application.register-mode=all
# 可选值 interface、instance、all,默认是 all,即接口级地址、应用级地址都注册

另外,可以在配置中心修改全局默认行为,来控制所有 3.x 实例注册行为。其中,全局性开关的优先级低于 -D 参数。

为了保证平滑迁移,即升级到 3.x 的实例能同时被 2.x 与 3.x 的消费者实例发现,3.x 实例需要开启双注册;当所有上游的消费端都迁移到 3.x 的地址模型后,提供端就可以切换到 instance 模式(只注册应用级地址)。对于如何升级消费端到 3.x 请参见下一小节。

1.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 的数据量。

1.3 Consumer 端升级过程

对于 2.x 的消费者实例,它们看到的自然都是 2.x 版本的提供者地址列表;

对于 3.x 的消费者,它具备同时发现 2.x 与 3.x 提供者地址列表的能力。在默认情况下,如果集群中存在可以消费的 3.x 的地址,将自动消费 3.x 的地址,如果不存在新地址则自动消费 2.x 的地址。Dubbo3 提供了开关来控制这个行为:

dubbo.application.service-discovery.migration=APPLICATION_FIRST
# 可选值 
# FORCE_INTERFACE,只消费接口级地址,如无地址则报错,单订阅 2.x 地址
# APPLICATION_FIRST,智能决策接口级/应用级地址,双订阅
# FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址

dubbo.application.service-discovery.migration 支持通过 -D 以及 全局配置中心 两种方式进行配置。

在这里插入图片描述

接下来,我们就具体看一下,如何通过双订阅模式(APPLICATION_FIRST)让升级到 3.x 的消费端迁移到应用级别的地址。在具体展开之前,先明确一条消费端的选址行为:对于双订阅的场景,消费端虽然可同时持有 2.x 地址与 3.x 地址,但选址过程中两份地址是完全隔离的:要么用 2.x 地址,要么用 3.x 地址,不存在两份地址混合调用的情况,这个决策过程是在收到第一次地址通知后就完成了的

1.3.1 APPLICATION_FIRST策略

首先,提前在全局配置中心 Nacos 配置一条配置项(所有消费端都将默认执行这个选址策略):

//imgs/v3/migration/nacos-migration-item.png

紧接着,升级消费端到 3.x 版本并启动,这时消费端读取到APPLICATION_FIRST配置后,执行双订阅逻辑订阅 2.x 接口级地址与 3.x 应用级地址

至此,升级操作就完成了,剩下的就是框架内部的执行了。在调用发生前,框架在消费端会有一个“选址过程”,注意这里的选址和之前 2.x 版本是有区别的,选址过程包含了两层筛选

  • 先进行地址列表(ClusterInvoker)筛选(接口级地址 or 应用级地址)
  • 再进行实际的 provider 地址(Invoker)筛选。
    //imgs/v3/migration/migration-cluster-item.png

ClusterInvoker 筛选的依据,可以通过 MigrationAddressComparator SPI 自行定义,目前官方提供了一个简单的地址数量比对策略,即当 应用级地址数量 == 接口级地址数量 满足时则进行迁移。

其实 FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION 控制的都是这里的 ClusterInvoker 类型的筛选策略

1.3.2 双订阅带来的资源消耗

双订阅不可避免的会增加消费端的内存消耗,但由于应用级地址发现在地址总量方面的优势,这个过程通常是可接受的,我们从两个方面进行分析:

  1. 双订阅带来的地址推送数据量增长。这点我们在 ”2.1 双注册带来的资源消耗“ 中做过介绍,应用级服务发现带来的注册中心数据量增长非常有限。
  2. 双订阅带来的消费端内存增长。要注意双订阅只存在于启动瞬态,在ClusterInvoker选址决策之后其中一份地址就会被完全销毁;对单个服务来说,启动阶段双订阅带来的内存增长大概能控制在原内存量的 30% ~ 40%,随后就会下降到单订阅水平,如果切到应用级地址,能实现内存 50% 的下降。

1.3.3 消费端更细粒度的控制

除了全局的迁移策略之外,Dubbo 在消费端提供了更细粒度的迁移策略支持。控制单位可以是某一个消费者应用,它消费的服务A、服务B可以有各自独立的迁移策略,具体是用方式是在消费端配置迁移规则:

key: demo-consumer
step: APPLICATION_FIRST
applications:- name: demo-providerstep: FORCE_APPLICATION
services:- serviceKey: org.apache.dubbo.config.api.DemoService:1.0.0step: FORCE_INTERFACE

使用这种方式能做到比较精细迁移控制,但是当下及后续的改造成本会比较高,除了一些特别场景,我们不太推荐启用这种配置方式。 迁移指南官方推荐使用的全局的开关式的迁移策略,让消费端实例在启动阶段自行决策使用哪份可用的地址列表。

1.4 迁移状态的收敛

为了同时兼容 2.x 版本,升级到 3.x 版本的应用在一段时间内要么处在双注册状态,要么处在双订阅状态。

解决这个问题,我们还是从 Provider 视角来看,当所有的 Provider 都切换到应用级地址注册之后,也就不存在双订阅的问题了。

1.4.1 不同的升级策略影响很大

毫无疑问越早越彻底的升级,就能尽快摆脱这个局面。设想,如果可以将组织内所有的应用都升级到 3.x 版本,则版本收敛就变的非常简单:升级过程中 Provider 始终保持双注册,当所有的应用都升级到 3.x 之后,就可以调整全局默认行为,让 Provider 都变成应用级地址单注册了,这个过程并不会给 Consumer 应用带来困扰,因为它们已经是可以识别应用级地址的 3.x 版本了。

如果没有办法做到应用的全量升级,甚至在相当长的时间内只能升级一部分应用,则不可避免的迁移状态要持续比较长的时间。 在这种情况下,我们追求的只能是尽量保持已升级应用的上下游实现版本及功能收敛。推动某些 Provider 的上游消费者都升级到 Dubbo3,这样就可以解除这部分 Provider 的双注册,要做到这一点,可能需要一些辅助统计工具的支持。

  1. 要能分析出应用间的依赖关系,比如一个 Provdier 应用被哪些消费端应用消费,这可以通过 Dubbo 提供的服务元数据上报能力来实现。
    2.要能知道每个应用当前使用的 dubbo 版本,可以通过扫描或者主动上报手段。

2. 迁移规则说明

2.1 状态模型

Dubbo 3 之前地址注册模型是以接口级粒度注册到注册中心的,而 Dubbo 3 全新的应用级注册模型注册到注册中心的粒度是应用级的。从注册中心的实现上来说是几乎不一样的,这导致了对于从接口级注册模型获取到的 invokers 是无法与从应用级注册模型获取到的 invokers 进行合并的。为了帮助用户从接口级往应用级迁移,Dubbo 3 设计了 Migration 机制,基于三个状态的切换实现实际调用中地址模型的切换。

//imgs/v3/migration/migration-1.png

当前共存在三种状态,FORCE_INTERFACE(强制接口级),APPLICATION_FIRST(应用级优先)、FORCE_APPLICATION(强制应用级)。

  • FORCE_INTERFACE:只启用兼容模式下接口级服务发现的注册中心逻辑,调用流量 100% 走原有流程
  • APPLICATION_FIRST:开启接口级、应用级双订阅,运行时根据阈值和灰度流量比例动态决定调用流量走向
  • FORCE_APPLICATION:只启用新模式下应用级服务发现的注册中心逻辑,调用流量 100% 走应用级订阅的地址

2.2 规则体说明

规则采用 yaml 格式配置,具体配置下参考如下:

key: 消费者应用名(必填)
step: 状态名(必填)
threshold: 决策阈值(默认1.0)
proportion: 灰度比例(默认100)
delay: 延迟决策时间(默认0)
force: 强制切换(默认 false)
interfaces: 接口粒度配置(可选)- serviceKey: 接口名(接口 + : + 版本号)(必填)threshold: 决策阈值proportion: 灰度比例delay: 延迟决策时间force: 强制切换step: 状态名(必填)- serviceKey: 接口名(接口 + : + 版本号)step: 状态名
applications: 应用粒度配置(可选)- serviceKey: 应用名(消费的上游应用名)(必填)threshold: 决策阈值proportion: 灰度比例delay: 延迟决策时间force: 强制切换step: 状态名(必填)

参数说明:

  • key: 消费者应用名
  • step: 状态名(FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION)
  • threshold: 决策阈值(浮点数,具体含义参考后文)
  • proportion: 灰度比例(0~100,决定调用次数比例)
  • delay: 延迟决策时间(延迟决策的时间,实际等待时间为 1~2 倍 delay 时间,取决于注册中心第一次通知的时间,对于目前 Dubbo 的注册中心实现次配置项保留 0 即可)
  • force: 强制切换(对于 FORCE_INTERFACE、FORCE_APPLICATION 是否不考虑决策直接切换,可能导致无地址调用失败问题)
  • interfaces: 接口粒度配置

参考配置示例如下

key: demo-consumer
step: APPLICATION_FIRST
threshold: 1.0
proportion: 60
delay: 0
force: false
interfaces:- serviceKey: DemoService:1.0.0threshold: 0.5proportion: 30delay: 0force: truestep: APPLICATION_FIRST- serviceKey: GreetingService:1.0.0step: FORCE_APPLICATION

2.3 配置方式说明

2.3.1. 配置中心配置文件下发(推荐)

  • Key: 消费者应用名 + “.migration”
  • Group: DUBBO_SERVICEDISCOVERY_MIGRATION
    配置项内容参考上一节

程序启动时会拉取此配置作为最高优先级启动项,当配置项为启动项时不执行检查操作,直接按状态信息达到终态。 程序运行过程中收到新配置项将执行迁移操作,过程中根据配置信息进行检查,如果检查失败将回滚为迁移前状态。迁移是按接口粒度执行的,也即是如果一个应用有 10 个接口,其中 8 个迁移成功,2 个失败,那终态 8 个迁移成功的接口将执行新的行为,2 个失败的仍为旧状态。如果需要重新触发迁移可以通过重新下发规则达到。

注:如果程序在迁移时由于检查失败回滚了,由于程序无回写配置项行为,所以如果此时程序重启了,那么程序会直接按照新的行为不检查直接初始化。

2.3.2 启动参数配置

  • 配置项名:dubbo.application.service-discovery.migration
  • 允许值范围:FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION

此配置项可以通过环境变量或者配置中心传入,启动时优先级比配置文件低,也即是当配置中心的配置文件不存在时读取此配置项作为启动状态。

2.3.3 本地文件配置

配置项名默认值说明
dubbo.migration.filedubbo-migration.yaml本地配置文件路径
dubbo.application.migration.delay60000配置文件延迟生效时间(毫秒)

配置文件中格式与前文提到的规则一致

本地文件配置方式本质上是一个延时配置通知的方式,本地文件不会影响默认启动方式,当达到延时时间后触发推送一条内容和本地文件一致的通知。这里的延时时间与规则体中的 delay 字段无关联。 本地文件配置方式可以保证启动以默认行为初始化,当达到延时时触发迁移操作,执行对应的检查,避免启动时就以终态方式启动。

2.4 决策说明

2.4.1 阈值探测

阈值机制旨在进行流量切换前的地址数检查,如果应用级的可使用地址数与接口级的可用地址数对比后没达到阈值将检查失败。

核心代码如下:

if (((float) newAddressSize / (float) oldAddressSize) >= threshold) {return true;
}
return false;

同时 MigrationAddressComparator 也是一个 SPI 拓展点,用户可以自行拓展,所有检查的结果取交集。

2.4.2 灰度比例

灰度比例功能仅在应用级优先状态下生效。此功能可以让用户自行决定调用往新模式应用级注册中心地址的调用数比例。灰度生效的前提是满足了阈值探测,在应用级优先状态下,如果阈值探测通过,currentAvailableInvoker 将被切换为对应应用级地址的 invoker;如果探测失败 currentAvailableInvoker 仍为原有接口级地址的 invoker。

流程图如下:
探测阶段
在这里插入图片描述

调用阶段
在这里插入图片描述

核心代码如下:

// currentAvailableInvoker is based on MigrationAddressComparator's result
if (currentAvailableInvoker != null) {if (step == APPLICATION_FIRST) {// call ratio calculation based on random valueif (ThreadLocalRandom.current().nextDouble(100) > promotion) {return invoker.invoke(invocation);}}return currentAvailableInvoker.invoke(invocation);
}

2.5 切换过程说明

地址迁移过程中涉及到了三种状态的切换,为了保证平滑迁移,共有 6 条切换路径需要支持,可以总结为从强制接口级、强制应用级往应用级优先切换;应用级优先往强制接口级、强制应用级切换;还有强制接口级和强制应用级互相切换。 对于同一接口切换的过程总是同步的,如果前一个规则还未处理完就收到新规则则回进行等待。

2.5.1 切换到应用级优先

从强制接口级、强制应用级往应用级优先切换本质上是从某一单订阅往双订阅切换,保留原有的订阅并创建另外一种订阅的过程。这个切换模式下规则体中配置的 delay 配置不会生效,也即是创建完订阅后马上进行阈值探测并决策选择某一组订阅进行实际优先调用。由于应用级优先模式是支持运行时动态进行阈值探测,所以对于部分注册中心无法启动时即获取全量地址的场景在全部地址通知完也会重新计算阈值并切换。 应用级优先模式下的动态切换是基于服务目录(Directory)的地址监听器实现的。

在这里插入图片描述

2.5.2 应用级优先切换到强制

应用级优先往强制接口级、强制应用级切换的过程是对双订阅的地址进行检查,如果满足则对另外一份订阅进行销毁,如果不满足则回滚保留原来的应用级优先状态。 如果用户希望这个切换过程不经过检查直接切换可以通过配置 force 参数实现。
在这里插入图片描述

2.5.3 强制接口级和强制应用级互相切换

强制接口级和强制应用级互相切换需要临时创建一份新的订阅,判断新的订阅(即阈值计算时使用新订阅的地址数去除旧订阅的地址数)是否达标,如果达标则进行切换,如果不达标会销毁这份新的订阅并且回滚到之前的状态。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/12912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java—如何判断两个浮点数相等

结论 一旦有浮点型数据参与运算的结果,一定不要使用 “ ” 与其比较。 提出问题 我们知道在Java中浮点数float 和 double 的值不能很精准的表示一个小数,因为会有精度损失。 下面来看一个例子: public class FloatTest {public static …

戒烟网站|基于SSM+vue的戒烟网站系统的设计与实现(源码+数据库+文档)

戒烟网站 目录 基于SSM+vue的戒烟网站系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1网站功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主…

使用单目相机前后帧特征点匹配进行3D深度估计的方法

在计算机视觉和机器人领域,三维空间感知是实现环境理解和交互的核心技术之一。特别是在资源受限的场合,使用针孔模型的单目相机进行深度估计成为了一种既经济又实用的解决方案。单目深度估计技术依赖于从连续视频帧中提取和匹配特征点,以估计…

理解JavaScript递归

什么是递归 程序调用自身的编程技巧称为递归(recursion) 递归的基本思想是将一个复杂的问题分解成更小、更易于管理的子问题,这些子问题与原始问题相似,但规模更小。 递归的要素 基本情况(Base Case)&…

2024年第十届中西部外语翻译大赛

2024年第十届中西部外语翻译大赛 竞赛信息 “由中西部翻译协会共同体指导发起,各省市译协共建学术指导委员会,2024年第十届中西部外语翻译大赛由中西部翻译协会共同体秘书处(武汉公仪网络科技有限公司)承办。” - 获奖证书样图 -…

开发板连接电机,烧坏芯片的原因、解决

当使用开发板、核心板,连接电机驱动板,控制电机的转动,会很容易烧芯片。 极少数是通电就烧坏,有些是调试了一段时间才烧,也有些是稳定运行好些日子突然烧了...... 百度搜索:“STM32 电机 烧坏”&#xff…

python文件操作常用方法(读写txt、xlsx、CSV、和json文件)

引言 用代码做分析的时候经常需要保存中间成果,保存文件格式各不相同,在这里好好总结一下关于python文件操作的方法和注意事项 Python 提供了丰富的文件操作功能,允许我们创建、读取、更新和删除文件。允许程序与外部世界进行交互。 文章目录…

【C++】从零开始构建二叉搜索树

送给大家一句话: 我们始终有选择的自由。选错了,只要真诚的反思,真诚面对,也随时有机会修正错误和选择。 – 《奇迹男孩(电影)》 💻💻💻💻💻💻💻…

数据资源入表难在哪?今晚带你一一弄懂(文末有福利)

​本周,我们即将开启数据要素系列直播《星光对话》的第四期,将由讲师-星光数智首席数据架构师 魏战松,于今晚19:00带来《数据资源入表和运营路径》的主题分享。 精彩内容提前知: 1、入表流程及各阶段参与方 2、入表难点和注意事项…

Android中使用Palette让你的页面UI优雅起来

文章目录 1. 什么是Palette2. 引入Palette3. 使用 Palette3.1 同步方式3.2 异步方式3.3 获取色调值 4. 举例4.1 布局文件 activity_palette_list.xml ⬇️4.2 Activity:PaletteListActivity⬇️4.3 列表Adapter:PaletteListAdapter ⬇️4.4 列表item布局…

「Python绘图」绘制同心圆

python 绘制同心圆 一、预期结果 二、核心代码 import turtle print("开始绘制同心圆") # 创建Turtle对象 pen turtle.Turtle() pen.shape("turtle") # 移动画笔到居中位置 pen.pensize(2) #设置外花边的大小 # 设置填充颜色 pen.fillcolor("green&…

java 并发线程应用

java 并发线程相关 线程状态 新建(NEW): 创建后尚未启动。可运行(RUNABLE): 正在 Java 虚拟机中运行。但是在操作系统层面,它可能处于运行状态,也可能等待资源调度(例如处理器资源),资源调度完成就进入运行状态。所以该状态的可运行是指可以被运行,具体有没有运行要看底层…

【C++算法】堆相关经典算法题

1.最后一块石头的重量 其实就是一个模拟的过程:每次从石堆中拿出最大的元素以及次大的元素,然后将它们粉碎;如果还有剩余,就将剩余的石头继续放在原始的石堆里面重复上面的操作,直到石堆里面只剩下一个元素&#xff0c…

[C/C++] -- 装饰器模式

装饰器模式是一种结构型设计模式,它允许在不改变原始对象的基础上动态地扩展其功能。这种模式通过将对象包装在装饰器类的对象中来实现,每个装饰器对象都包含一个原始对象,并可以在调用原始对象的方法之前或之后执行一些额外的操作。 装饰器…

自学C语言能达到什么境界呢?

C 语言是一门广泛应用于系统软件、嵌入式系统、游戏开发等领域的编程语言。那么,通过自学 C 语言,能够达到什么样的境界呢? 就像学习小提琴一样,仅凭自学也可以达到一定的水平,能够自娱自乐,在亲友聚会时表…

Xed编辑器开发第一期:使用Rust从0到1写一个文本编辑器

这是一个使用Rust实现的轻量化文本编辑器。学过Rust的都知道,Rust 从入门到实践中间还隔着好几个Go语言的难度,因此,如果你也正在学习Rust,那么恭喜你,这个项目被你捡到了。本项目内容较多,大概会分三期左右陆续发布&a…

NAS导航面板Sun-Panel

什么是 Sun-Panel ? Sun-Panel 是一个服务器、NAS 导航面板、Homepage、浏览器首页。 软件主要特点: 🍉 界面简洁,功能强大,资源消耗低🍊 简单易用,可视化操作,零代码使用&#x1f…

python怎么安装matplotlib

1、登陆官方网址“https://pypi.org/project/matplotlib/#description”,下载安装包。 2、选择合适的安装包,下载下来。 3、将安装包放置到python交互命令窗口的当前目录下。 4、打开windows的命令行窗口,通过"pip install"这个命令…

新质生产力之工业互联网产业链

随着全球经济的数字化转型,新基建的概念逐渐成为推动工业发展的关键动力。在这一转型过程中,工业互联网作为新基建的核心组成部分,正逐渐塑造着未来工业的面貌。那么工业互联网产业链是如何构成的,以及它如何成为推动工业4.0和智能…