实践案例:同程艺龙网的 Dubbo 升级经验总结
本篇为同程艺龙旅行网 Apache Dubbo 的实践案例总结。感兴趣的朋友可以访问官网了解更多详情,或搜索关注官方微信公众号
Apache Dubbo
跟进最新动态。
作者信息:
- 严浩:同程艺龙高级开发,负责服务治理相关工作, Apache Dubbo Committer。
- 胥皓:同程艺龙高级开发,负责服务治理相关工作。
Dubbo3在同程旅行的实践
背景
在微服务发展初期,市场上还没有成熟和流行的 RPC 框架,我们公司内部自研开发了一套名为 DSF (Distributed Service Framework) 的 RPC 框架,支撑起了公司业务的高速发展。但是随着技术的快速迭代和人员的不断变更,开发者既要修复之前的 BUG 又要跟上技术的更新,开发维护成本越来越高。另一方面,现在应用程序都在往云原生方向发展与设计,公司也在这方面做出探索。因此公司微服务框架的演进已经到了岔路口,是全新升级原有的 SDK,还是选择拥抱开源?
考虑到升级现有的 SDK 在一段时间之后可能依然会面临现在的问题,最后我们选择了拥抱开源。在一番调研之后我们选择了 Dubbo3 作为公司的下一代 RPC 框架,担任微服务治理体系的数据面。
目前 Dubbo3 在公司的落地开发工作已经完成,通过本文我们对公司内部 Dubbo3 的实践及收益做了深入总结。
Dubbo3 核心功能介绍
Dubbo 社区关于 Dubbo 3 的文档和资料越来越完善,以下是我们从社区引用的一些内容。
Dubbo3 被社区寄予厚望,将其视为下一代云原生服务框架打造,Dubbo3 提供的核心特性列表,主要包括四部分。
- 全新服务发现模型。应用粒度服务发现,面向云原生设计,适配基础设施与异构系统;性能与集群伸缩性大幅提升。
- 下一代 RPC 协议 Triple。基于 HTTP/2 的 Triple 协议,兼容 gRPC;网关穿透性强、多语言友好、支持 Reactive Stream。
- 统一流量治理模型。面向云原生流量治理,SDK、Mesh、VM、Container 等统一治理规则;能够支持更丰富的流量治理场景。
- Service Mesh。在最新的3.1.0的版本中支持Sidecar Mesh 与 Proxyless Mesh,提供更多架构选择,降低迁移、落地成本。
Dubbo3 的核心功能点(如应用级服务发现以 ip、port 为区分实例)和公司内部的服务模型一致,极大地减少了我们的适配工作。还有在 Service Mesh 中对 Sidecar Mesh 与 Proxyless Mesh 的支持也将减少后续公司对 Mesh 方案的探索成本,包括 Dubbo3 在多语言体系的发展也为异构架构提供了支撑。
总的来说,Dubbo3 非常契合公司的技术体系和后续的发展方向。此外,Dubbo 在开发者中的熟悉度、社区的高活跃度和完善的文档建设也都能为推动 Dubbo3 的使用带来不少的帮助。
方案调研
在了解了 Dubbo3 的核心功能和基本工作原理之后我们开始前期工作阶段。
公司内部存在微服务体系 RPC 框架 DSF 和承担服务发现、路由、上下负载等功能的控制中心,如果让用户直接切换到 Dubbo3 使用完全隔离的一套微服务体系会对用户带来高额的升级和切换成本。所以我们选择用 Dubbo3 替换之前的 DSF 框架作为数据面,将 Dubbo3 接入当前的微服务控制中心。同时要求 Dubbo3 支持原有 DSF 框架的私有协议,与 DSF 框架能够相互发现和调用,进一步降低用户升级成本。
这样用户在编程习惯上和 Dubbo3 的使用完全保持一致,在服务治理上(如上下负载、同中心路由、实例标签等功能)的使用与 DSF 保持一致。由于协议兼容,新的 Dubbo3 应用和原有 DSF 应用之间也能实现互相发现和调用。
要完成这个目标,需要去拓展 Dubbo3 SDK 的注册模块支持从现有的控制中心进行服务注册与发现、扩展自定义协议与 DSF 服务相互调用。借助于Dubbo 强大的插件机制,我们在没有修改 Dubbo 框架任何代码的基础上轻松地完成了这个目标,用户只需要引入 Dubbo 3.0 以上版本的 SDK 和我们开发的插件包即可。
整体的架构流程如下:
Dubbo3 落地的方案需要满足以下三点要求:
- Dubbo3 要接入现有的控制中心,由控制中心完成服务注册发现和服务治理功能;
- Dubbo3 能够和 DSF 能够相互调用,满足此要求需要两个框架能够互相服务发现并且协议能够兼容;
- 通过插件机制完成所有功能,不能修改 Dubbo 源码,用户可以自由地升级 Dubbo3 SDK 的版本;
服务注册发现兼容
既然需要将 Dubbo3 的应用级注册接入到控制中心,而且需要与 DSF 服务进行服务发现,就需要了解 Dubbo3 应用级发现的流程才能对其进行更好的拓展。
应用级服务发现核心原理
我们从 Dubbo 最经典的工作原理图说起。Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,Consumer 基于特定的负载均衡策略发起对 Provider 的 RPC 调用。
在这个过程中:
- 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址;
- 注册中心通过这个 key 对 Provider 实例地址进行聚合;
- Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表;
可以看到接口级服务发现是以接口为维度进行服务注册的,并在注册数据上携带了服务的配置和元数据。这种方式简单易用而且可以轻松实现应用、接口、方法粒度的服务治理。但由此带来的注册数据的放大问题会给注册中心造成较大压力,还有就是与现在云原生的服务模型并不兼容,不能与 Kubernetes 兼容。
面对这些不足,在 Dubbo3 架构下社区认真思考了两个问题:
- 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo 3 能支撑更大规模集群水平扩容?
- 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通?
最终,社区给出的方案也是非常巧妙和经典,将之前接口级服务的数据拆成两部分。属于实例模型的 ip 和 port 注册到注册中心,而属于业务属性的 RPC 元数据和 RPC 服务配置统一由 Dubbo Provider 的 MetadataService RPC 服务提供或者由元数据中心提供。在服务消费端和提供端之间建立了一条内置的 RPC 服务信息协商机制,也称为"服务自省"。全新的应用级服务发现模型,相比之前接口级别单机内存下降 50% 且极大的减少了注册中心的压力。
还有一个问题是换成了应用级服务发现之后,Consumer 是如何知道订阅的接口是属于哪一个服务的?因为 Dubbo 的编程模型是以接口为维度的。Dubbo3 提供了两种解决方案:一是从元数据中心存储接口和应用名的映射关系,二是通过 Consumer 在接口上通过 providerBy 配置手动指定服务提供方的名称。
兼容方案
如果是 Dubbo Consumer 调用 Dubbo Provider,我们只需要按部就班参考其他应用级别服务发现的插件比如 Zookeeper、Nacos 开发就可以完成此功能。如果 DSF Client 要调用 Dubbo Provider 我们是将兼容逻辑放在了控制中心,避免用户 SDK 的升级成本。剩下的兼容流程只有 Dubbo Consumer 调用 DSF Server 了,因为要求尽量不要修改 Dubbo 框架的源码,所以这里的兼容逻辑我们只能在注册中心的插件中完成。
上面介绍应用级服务发现的核心原理的时候提到应用级服务发现有 3 个关键的步骤
- 通过元数据的 mapping 获取接口对应的服务名或者通过接口配置中的 providerBy 指定;
- 通过服务名获取实例列表,实例以 ip、port 为维度,并且在实例信息中携带元数据的 revision;
- 调用 Dubbo Provider 的 MetaService 获取实例的元数据信息,组装接口数据;
Dubbo 服务 调用 DSF 服务兼容流程的第一步非常简单,因为 DSF 并没有接口与服务名的 mapping 数据,所以通过 providerBy 指定接口所属的 DSF 服务名。第二步因为 DSF 服务的注册模型也是应用级的,实例的数据完全可以兼容这一部分也很简单。最关键的一步在于如何获取 DSF 服务的元数据,很显然现有的 DSF 服务并不具有 MetaService 的接口。
上面提到 Dubbo3 支持两种方式获取实例的元数据。默认就是从 Dubbo Provider 的 MetaService 获取实例的元数据信息,也支持从元数据中心获取实例的元数据信息,只需要将实例的 dubbo.metadata.storage-type 属性设置为 remote 即可。而 DSF 服务正好发布了 API 的契约数据到控制中心用作服务测试和寻址兼容,完全可以将 DSF 的契约数据转换为 Dubbo 的元数据的格式,满足服务发现的流程。
以下为 Dubbo Consumer 发现 DSF 服务的流程
完成服务发现的兼容之后,用户在调用 DSF 服务的时候仅需要在接口上通过 providerBy 指定接口对应的服务即可,使用成本极低。
协议兼容与服务治理
协议兼容
完成服务发现的相互兼容之后,离 Dubbo 与 DSF 服务的相互调用的目标只剩最后一块拼图,在插件中实现 DSF 协议即可。
相比服务发现的各种数据兼容,协议的兼容比较清晰,只需要根据 Dubbo 协议扩展说明进行自定义协议扩展完成 DSF 数据格式兼容即可。
Dubbo 协议扩展需要实现以下接口:
org.apache.dubbo.rpc.Exporter
org.apache.dubbo.rpc.Invoker
org.apache.dubbo.rpc.Protocol
当用户调用 refer()
所返回的 Invoker
对象的 invoke()
方法时,协议需相应执行同 URL 远端 export()
传入的 Invoker
对象的 invoke()
方法。其中,refer()
返回的 Invoker
由协议实现,协议通常需要在此 Invoker
中发送远程请求,export()
传入的 Invoker
由框架实现并传入,协议不需要关心。也就是说服务提供方在容器启动的时候就进行服务的暴露,而服务调用方需要通过协议进行Invoker的调用。我们的扩展如下:
最后完成的效果如下,用户只需要在 pom 中引入 Dubbo3 以上的任意版本和开发的插件,配置上指定注册中心地址和协议为 dsf 即可,其他使用方式和 Dubbo3 保持一致。
<properties>
<dubbo.version>3.0.11</dubbo.version>
<dubbo-dsf.version>1.0.0</dubbo-dsf.version>
</properties>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.ly.dsf</groupId>
<artifactId>dubbo-dsf-extensions-all</artifactId>
<version>${dubbo-dsf.version}</version>
</dependency>
配置文件
# 注册地址为控制中心
dubbo.registry.address=dsf://{address}
# 协议指定 dsf
dubbo.protocol.name=dsf
dubbo.consumer.protocol=dsf
服务治理
Dubbo3 有非常强大的流量治理的功能,同时我们内部的控制中心也有服务治理的功能,部分功能也有重合。
对于这部分的取舍,我们打算控制中心原有的功能对 Dubbo3 服务依然支持,如服务发现、同中心寻址、上下负载、服务测试等操作和之前保持一致。而 Dubbo 特有的服务治理功能如动态配置、Mesh 路由,我们将新增功能对其支持,保证 Dubbo3 功能的完整。
总结
Dubbo 3 是一个优秀的微服务框架,提供的 SPI 以及 Extension 机制能够非常方便的让用户去扩展实现想要功能。而且 Dubbo3 也更适应目前云原生的架构,Dubbo 3.1.x 版本支持 Sidecar 和 Proxyless 的 Mesh 方案,而且社区也在准备开源 Java Agent 方式的 Proxyless,这样就能较好的将微服务架框的 Framework 与数据面解耦,降低微服务框架的维护成本和升级成本。我们也会和社区一起探索,共建 Dubbo 社区的繁荣。
搜索关注官方微信公众号:Apache Dubbo,了解更多业界最新动态,掌握大厂面试必备 Dubbo 技能
实践案例:同程艺龙网的 Dubbo 升级经验总结的更多相关文章
- DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能
DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能 一.引言 在当前的电子商务平台中,用户下完订单之后,然后店家会在后台看到客户下的订单,然后店家可以对客户的订单进行发货操作.此时客户会在自己 ...
- 微服务实战(四):服务发现的可行方案以及实践案例 - DockOne.io
原文:微服务实战(四):服务发现的可行方案以及实践案例 - DockOne.io 这是关于使用微服务架构创建应用系列的第四篇文章.第一篇介绍了微服务架构的模式,讨论了使用微服务架构的优缺点.第二和第三 ...
- - 反编译 AndroidKiller 逆向 实践案例 MD
目录 目录 反编译 AndroidKiller 逆向 实践案例 MD AndroidKiller 简介 插件升级 基本使用 实践案例 修改清单文件 打印 debug 级别的日志 方式一:直接代理 Lo ...
- 《SaltStack技术入门与实践》—— 实践案例 <中小型Web架构>3 Memcached配置管理
实践案例 <中小型Web架构>3 Memcached配置管理 本章节参考<SaltStack技术入门与实践>,感谢该书作者: 刘继伟.沈灿.赵舜东 Memcached介绍 Me ...
- React Native实践之携程Moles框架
编者:本文来自携程框架研发部高级经理魏晓军在第二期[携程技术微分享]上的分享,以下为整理后的文字实录.视频回放可点击这里.关注携程技术中心微信公号ctriptech,可获知更多微分享课程信息. 因为支 ...
- Hadoop家族学习路线、实践案例
作者:Han Hsiao链接:https://www.zhihu.com/question/19795366/answer/24524910来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...
- 爬虫学习(十二)——bs4实践案例
实践项目————诗词名句网<三国演义>小说爬取 import osimport reimport timeimport urllib.requestimport urllib.parsef ...
- ES业界优秀实践案例汇总
ES业界优秀案例汇总 携程 LinkedIn Etsy国外电商CPU(vCore) 70*32 1000*12 4200单日索引数据条数 600亿 500亿 100亿单核处理数据性能/天 2600万/ ...
- 数据库周刊30丨数据安全法草案将亮相;2020数据库产业报告;云南电网上线达梦;达梦7误删Redo Log;Oracle存储过程性能瓶颈;易鲸捷实践案例……
摘要:墨天轮数据库周刊第30期发布啦,每周1次推送本周数据库相关热门资讯.精选文章.干货文档. 热门资讯 1.数据安全法草案即将亮相:将确立数据分级分类管理.应急处置制度[摘要]数据安全法草案即将在本 ...
- redis入门到精通系列(二):redis操作的两个实践案例
在前面一篇博客中我们已经学完了redis的五种数据类型操作,回顾一下,五种操作类型分别为:字符串类型(string).列表类型(list).散列类型(hash).集合类型(set).有序集合类型(so ...
随机推荐
- 【全网最全】springboot整合JSR303参数校验与全局异常处理
一.前言 我们在日常开发中,避不开的就是参数校验,有人说前端不是会在表单中进行校验的吗?在后端中,我们可以直接不管前端怎么样判断过滤,我们后端都需要进行再次判断,为了安全.因为前端很容易拜托,当测试使 ...
- Kubernetes 监控--PromQL
Prometheus 通过指标名称(metrics name)以及对应的一组标签(label)唯一定义一条时间序列.指标名称反映了监控样本的基本标识,而 label 则在这个基本特征上为采集到的数据提 ...
- Elastic:创建你的第一个Elastic alert
文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/105340379 在Elasticsearch可以提供给我们数据的存储及快速的搜索,但 ...
- kvm上已安装的虚拟机修改为桥接网络
kvm上安装的虚拟机默认使用的nat网络格式,现在已经调整kvm主机为桥接方式了,但是已经安装的虚拟机还是nat方式,所以需要修改一下 让KVM虚拟主机使用桥接网络br0 修改虚拟机的配置文件,默认存 ...
- 为不同的用户生成不同的 Kibana 界面
文件转载自:https://elasticstack.blog.csdn.net/article/details/109593613
- 1-Mysql数据库简洁命令
1-进入mysql数据库 mysql -u root -p 2-创建数据库 mysql> CREATE DATABASE serurities_master; mysql> USE ser ...
- 面试突击86:SpringBoot 事务不回滚?怎么解决?
在 Spring Boot 中,造成事务不自动回滚的场景有很多,比如以下这些: 非 public 修饰的方法中的事务不自动回滚: 当 @Transactional 遇上 try/catch 事务不自动 ...
- Anaconda安装和卸载+虚拟环境Tensorflow安装以及末尾问题大全(附Anaconda安装包),这一篇就够了!!!
前言 实话说,在自己亲手捣鼓了一下午加一晚上后,本人深深地感受到了对于"Anaconda安装+虚拟环境Tensorflow安装"里面的坑点之多,再加上目前一些博主的资料有点久远,尤 ...
- count(*), count(1), count(列名)的区别
1.从结果上来看 count(1)和count(*)之间没有区别,因为count(*)count(1)都不会去过滤空值,但count(列名)就有区别了,因为count(列名)会去过滤空值. 2.从执行 ...
- AT&T汇编语法与x86语法基本区别
AT&T汇编和8086汇编语言虽然两者很相似,但是还是不能根据8086的语法规则来读AT&T汇编的吧,所以还是要看看AT&T汇编的语法规则,因为在读内核代码时,跟硬件打交道的部 ...