blob: 00a266dea713a4c299ee83eaab27259b4fab39d9 [file] [log] [blame]
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – 用户案例</title><link>https://dubbo.apache.org/zh-cn/blog/users/</link><description>Recent content in 用户案例 on Apache Dubbo</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><atom:link href="https://dubbo.apache.org/zh-cn/blog/users/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: 阿里巴巴升级 Dubbo3 全面取代 HSF2</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/16/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E5%8D%87%E7%BA%A7-dubbo3-%E5%85%A8%E9%9D%A2%E5%8F%96%E4%BB%A3-hsf2/</link><pubDate>Mon, 16 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/16/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E5%8D%87%E7%BA%A7-dubbo3-%E5%85%A8%E9%9D%A2%E5%8F%96%E4%BB%A3-hsf2/</guid><description>
&lt;p>继业务全面上云后,2022 双十一,阿里巴巴微服务技术栈全面迁移到以 Dubbo3 为代表的云上开源标准中间件体系。在业务上,基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的 Dubbo3 开源中间件体系打造了阿里在云上的单元化最佳实践和统一标准,同时将规模化实践经验与技术创新贡献开源社区,成为微服务开源技术与标准发展的核心源泉与推动力。&lt;/p>
&lt;h2 id="1-阿里电商">1 阿里电商&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649639544-2c49fc49-b25e-4fc9-845e-8b377ceba3bc.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=66&amp;amp;id=uf434669b&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=132&amp;amp;originWidth=204&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=13316&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u81ec2327-b1f6-43a2-b908-31b91796169&amp;amp;title=&amp;amp;width=102" alt="image.png"> &lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649088160-85a607de-4737-4e2d-90b2-49bf5b949332.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=81&amp;amp;id=l0QsD&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=162&amp;amp;originWidth=308&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=61949&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=ubb9c1593-7f65-4c84-997a-34e8e9b7f47&amp;amp;title=&amp;amp;width=154" alt="image.png"> &lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649669327-fe6b77b6-3f34-4a18-b5c6-726729b69331.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=74&amp;amp;id=ufc994d2f&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=148&amp;amp;originWidth=404&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=35362&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u2637ee3c-ea26-4a75-9a5c-2be5e913957&amp;amp;title=&amp;amp;width=202" alt="image.png"> &amp;hellip;&amp;hellip;&lt;/p>
&lt;p>整个电商体系的所有核心应用,包括交易相关、导购相关都都升级到了 Dubbo3 体系,用来替换原有的 HSF 框架,阿里电商是对 Dubbo3 实践最广泛、需求最强烈的体系,基于 Dubbo3 实现了以下关键目标。
2022 618大促、双11 大促期间 超 2000+ 应用、40w 节点均跑在 Dubbo3 之上。&lt;/p>
&lt;ul>
&lt;li>应用级服务发现,解决了大促期间地址推送降级的问题,部分关键链路提升单机资源利用率 40%,大促期间地址推送SLA保障、资源利用率。&lt;/li>
&lt;li>Triple协议,解决跨网关高效互通的问题,同时部分业务线升级了 Streaming 编程和通信模式。&lt;/li>
&lt;li>统一的流量治理规则,阿里电商场景的路由规则非常复杂,基于实现了云原生体系的结合。&lt;/li>
&lt;li>Service Mesh 解决方案,Thin SDK + Proxyless 的解决方案&lt;/li>
&lt;li>服务柔性,目前正在落地和探索自适应负载均衡、自适应限流等策略。&lt;/li>
&lt;/ul>
&lt;h2 id="2-蚂蚁金服">2 蚂蚁金服&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670648656034-5b9cfafc-899b-400b-9edb-4e6775febba4.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=46&amp;amp;id=ub2336156&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=66&amp;amp;originWidth=162&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=10659&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u79c80d75-a418-4b93-b16d-6c46304d343&amp;amp;title=&amp;amp;width=113" alt="image.png"> &lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649020622-256254e8-4ef1-43f6-b1c1-a9d29b80bdd1.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=57&amp;amp;id=uf2a1d369&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=114&amp;amp;originWidth=372&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=25430&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u685e5a50-cdcc-45d4-9806-f119df0d378&amp;amp;title=&amp;amp;width=186" alt="image.png"> &lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649055218-13ba694c-68e6-4e88-b981-a8db546839b0.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=59&amp;amp;id=ue3ffce18&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=118&amp;amp;originWidth=414&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=9958&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u25313916-0a19-4b21-a6c1-5da20a95dca&amp;amp;title=&amp;amp;width=207" alt="image.png">&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649088160-85a607de-4737-4e2d-90b2-49bf5b949332.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=81&amp;amp;id=ud329ff16&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=162&amp;amp;originWidth=308&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=61949&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=ubb9c1593-7f65-4c84-997a-34e8e9b7f47&amp;amp;title=&amp;amp;width=154" alt="image.png">&lt;/p>
&lt;p>阿里集团内与蚂蚁体系的互通,目前都跑在 Dubbo3 Triple 互通链路上,与原有基于 HSF 的互通方案对比,Triple 协议链路的 RT 降低了 50%。集团与蚂蚁东西向流量的核心链路,飞猪、手淘、口碑、饿了么、1688、部分导购应用、商品库、评价等业务都采用此方案。&lt;/p>
&lt;h2 id="3-本地生活">3 本地生活&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670648615017-544b873b-4bc3-4e17-8eac-87bf5d42cbf3.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=53&amp;amp;id=u397bea65&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=106&amp;amp;originWidth=308&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=15119&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u727184c0-ef5b-4156-91b9-8e927657a98&amp;amp;title=&amp;amp;width=154" alt="image.png"> &lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670650306384-a949c14f-191f-4537-b5d5-dc28844ca490.png#clientId=u8f193c04-9173-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=45&amp;amp;id=u0dfaf022&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=84&amp;amp;originWidth=272&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=20212&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u466a9278-caf7-40ad-ba03-d2fb168f83f&amp;amp;title=&amp;amp;width=147" alt="image.png">&lt;/p>
&lt;p>截止 2022 年初,Dubbo3 实现了在饿了么全量业务的生产上线,取代了之前自建的微服务体系,在过去的近一年时间内,饿了么线上有 2000 应用、15w 实例节点平稳跑在 Dubbo3 之上。&lt;/p>
&lt;p>饿了么成功升级 Dubbo3 及应用级服务发现模型,实现了和阿里电商系统互通、单元化体系互通架构的升级,实现了去 proxy 架构的目标,在饿了么关心的服务发现数据链路上:&lt;/p>
&lt;ul>
&lt;li>数据注册与订阅的传输量下降 90%&lt;/li>
&lt;li>注册中心数据存储的总体资源占用下降 90%&lt;/li>
&lt;li>消费端服务框架自身的常驻内存消耗下降达 50%&lt;/li>
&lt;/ul>
&lt;p>集群总体的稳定性、性能都得到明显提升,也为未来容量扩展做好准备。&lt;/p>
&lt;h2 id="4-钉钉">4 钉钉&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649135935-0d6804cc-00ca-4acb-a7b3-842377d1a6b0.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=57&amp;amp;id=u6203f26b&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=114&amp;amp;originWidth=266&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=10659&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=ufd0b0ffa-2aff-4ba9-83c7-764ae24a31a&amp;amp;title=&amp;amp;width=133" alt="image.png">&lt;/p>
&lt;p>钉钉核心业务在 2021 年实现了 Dubbo3 升级,基于 Triple 协议解决了云上、云下混合部署环境的互通问题。&lt;/p>
&lt;h2 id="5-阿里云">5 阿里云&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670649159068-ed9ba59b-9e3d-4268-be7e-c327227baa7b.png#clientId=u31fa6127-23e9-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=44&amp;amp;id=u90dcb125&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=88&amp;amp;originWidth=216&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=7597&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=ub661eabe-098b-4f30-b213-bd1b8dea581&amp;amp;title=&amp;amp;width=108" alt="image.png">&lt;/p>
&lt;p>阿里云公有云、转有云核心底座目前正全面迁移到 Dubbo3 体系,取代老版本的 Dubbo2 体系,预计本财年结束就能全部跑在 Dubbo3 之上。
除此之外,阿里云平台上的大部分对外售卖产品,目前都基于 Dubbo3 提供服务或提供 Dubbo3 支持,如微服务引擎MSE、达摩院店小蜜、教育平台、视频云业务等。&lt;/p>
&lt;h2 id="6-菜鸟">6 菜鸟&lt;/h2>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2022/png/54037/1670650418063-31eee85d-9e6a-474c-ade7-4a45fc956ae4.png#clientId=u8f193c04-9173-4&amp;amp;crop=0&amp;amp;crop=0&amp;amp;crop=1&amp;amp;crop=1&amp;amp;from=paste&amp;amp;height=64&amp;amp;id=ud036f280&amp;amp;margin=%5Bobject%20Object%5D&amp;amp;name=image.png&amp;amp;originHeight=128&amp;amp;originWidth=290&amp;amp;originalType=binary&amp;amp;ratio=1&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=13571&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=u8d7f509c-983a-483b-9fd9-00cf05f65c8&amp;amp;title=&amp;amp;width=145" alt="image.png">&lt;/p>
&lt;p>2022 年中下旬,菜鸟网络部分核心业务开始推进 Dubbo3 的全面升级,目前生产数据正在采集中。&lt;/p></description></item><item><title>Blog: 工商银行 Dubbo3 应用级服务发现实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B7%A5%E5%95%86%E9%93%B6%E8%A1%8C-dubbo3-%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E5%AE%9E%E8%B7%B5/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B7%A5%E5%95%86%E9%93%B6%E8%A1%8C-dubbo3-%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;h3 id="问题分析">问题分析&lt;/h3>
&lt;p>以下是经典的 Dubbo 的工作原理图,服务提供者和消费者通过注册中心协调实现地址的自动发现。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/icbc/icbc-analyze.png" alt="icbc-analyze">&lt;/p>
&lt;p>工商银行面临的主要瓶颈是在注册中心与服务消费端,接口级别地址的数量已经是亿级规模,一方面存储容量达到瓶颈、另一方面推送效率明显下降;而在消费端这一侧,Dubbo2 框架常驻内存已超 40%,每次地址推送带来的 cpu 等资源消耗率也非常高,影响正常的业务调用。&lt;/p>
&lt;p>这是 Dubbo2 接口级服务发现架构在大规模集群场景下的固有问题(具体原因请查看应用级服务发现原理解析),通过常规的性能优化无法从根本上解决问题。因此工商银行采用了 Dubbo3 中提出的应用级服务发现模型,经过实测,新的服务发现模型能实现节点到注册中心间数据传输量 90% 的下降,这就使得注册中心的压力极大降低,同时消费端的框架常驻内存也实现超 50% 下降。&lt;/p>
&lt;h3 id="压测数据">压测数据&lt;/h3>
&lt;p>下面是工商银行联合 Dubbo 社区给出的一组基于真实服务特点给出的模拟压测数据。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/icbc/icbc-data1.png" alt="icbc-data1">&lt;/p>
&lt;p>上图是对使用了应用级服务发现的消费端进程采样的内存对比数据。其中横轴是不同的 Dubbo 版本,纵轴是实际采样到的内存表现,可以看到 Dubbo 2.6、2.7 版本表现几乎一致,而升级到 3.0 版本后,即使不升级应用级服务发现,内存也降低接近 40%,而当切换到应用级服务发现之后,内存占用下降到只有原来的 30%。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/icbc/icbc-data2.png" alt="icbc-data2">&lt;/p>
&lt;p>上图是消费端的 GC 情况统计,同样的,横轴是不同的 Dubbo 版本,纵轴是实际采样到的 GC 表现。这里的压测数据,是通过模拟注册中心不停的往消费端进程推送地址列表的场景得到的。可以看到 Dubbo 2.6、2.7 版本表现几乎一致,而在 3.0 版本中切换到应用级服务发现之后,GC 已经趋近于零次。&lt;/p></description></item><item><title>Blog: 饿了么全站成功升级 Dubbo3</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E9%A5%BF%E4%BA%86%E4%B9%88%E5%85%A8%E7%AB%99%E6%88%90%E5%8A%9F%E5%8D%87%E7%BA%A7-dubbo3/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E9%A5%BF%E4%BA%86%E4%B9%88%E5%85%A8%E7%AB%99%E6%88%90%E5%8A%9F%E5%8D%87%E7%BA%A7-dubbo3/</guid><description>
&lt;h3 id="升级目标">升级目标&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-arc.png" alt="elem-arc">&lt;/p>
&lt;p>这里是饿了么的的基本部署架构图。&lt;/p>
&lt;p>在升级之前,饿了么的微服务框架采用的是 HSF2,跨单元的 RPC 调用是通过 proxy 中转代理,在这个过程中 proxy 所承载的机器数和流量迅速增长,比较突出的一点是 proxy 在订阅所有的地址数据后资源消耗和稳定性都收到严峻挑战。&lt;/p>
&lt;p>通过全站升级 Dubbo3,业务线期望达到两个目标:&lt;/p>
&lt;ul>
&lt;li>将地址模型切换到应用级服务发现大幅减轻中心化节点和消费端节点的资源消耗压力。&lt;/li>
&lt;li>以应用级服务发现架构下的全局共享注册中心取代 proxy 模式,实现跨单元节点通信直连。&lt;/li>
&lt;/ul>
&lt;h3 id="升级过程">升级过程&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-upgrade1.png" alt="eleme-upgrade1">&lt;/p>
&lt;p>不论是针对 Dubbo2 还是 HSF2,我们都做了全面的 API 兼容,因此 Dubbo3 基本可以做到零改造升级,并且每个应用都是独立透明升级,不需要关心它的上下游应用的升级状态,因为 Dubbo3 升级之后不论是从地址发现模型还是协议的默认行为都保持与 2.0 版本兼容,用户可以在任意时间点对任意应用按需切换 Dubbo3 行为。
如右图所示,我们模拟展示了饿了么集群 Dubbo3 升级过程的一个中间状态,其中灰色标记的是老版本 HSF2 应用,橙色和绿色标记的是已经升级 Dubbo3 的应用,橙色部分的应用及其调用链路代表不但已经升级到 Dubbo3,同时也完成了 Dubbo3 行为的切换,在这里是指已经切换到了应用级地址模型。这里的升级过程主要为了说明 Dubbo3 框架升级的兼容性和独立性。&lt;/p>
&lt;p>接下来,我们详细分析一下橙色部分节点往 Dubbo3 应用级发现迁移的具体过程。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-upgrade-provider.png" alt="elem-upgrade-provider">&lt;/p>
&lt;p>首先看 Provider 侧,服务提供者在升级 Dubbo3 后会默认保持双注册行为,即同时注册接口级地址和应用级地址到注册中心,一方面保持兼容,另一方面为未来消费端迁移做好准备。双注册的开关可通过 -Ddubbo.application.register-mode=al/interface/interface控制,我们推荐保持双注册的默认行为以减少后续迁移成本。&lt;/p>
&lt;p>大家可能担心双注册给注册中心带来的存储压力,实际上在应用级服务发现模型下这并不是一个问题,因为大家如果回想前面我们对应用级服务发现工作原理的分析,注册地址已经被大幅精简,根据我们实际推算,每多注册一条应用级服务发现 URL 地址,只会增加 0.1% ~ 1% 的额外开销。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-upgrade-consumer.png" alt="elem-upgrade-consumer">&lt;/p>
&lt;p>与提供端类似,要实现平滑迁移消费端也要经历双订阅的过程,流程上就不再赘述。消费端的双订阅行为也可通过规则或开关进行动态调整,控制消费端的消费的某个服务、应用迁移到应用级地址模型;除此之外,Dubbo3 还内置了自动决策机制,在发现应用级地址可用的情况下即会自动完成切换,并且这个行为是默认的。&lt;/p>
&lt;p>以下是消费端双订阅时的选址流程:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-upgrade-consumer1.png" alt="elem-upgrade-consumer1">&lt;/p>
&lt;h3 id="升级效果">升级效果&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/user/eleme/elem-result.png" alt="elem-result">&lt;/p>
&lt;p>饿了么成功升级 Dubbo3 及应用级服务发现模型,实现了去 proxy 架构的目标,在我们关心的服务发现数据链路上:&lt;/p>
&lt;ul>
&lt;li>数据注册与订阅的传输量下降 90%&lt;/li>
&lt;li>注册中心数据存储的总体资源占用下降 90%&lt;/li>
&lt;li>消费端服务框架自身的常驻内存消耗下降达 50%
集群总体的稳定性、性能都得到明显提升,也为未来容量扩展做好准备。&lt;/li>
&lt;/ul></description></item><item><title>Blog: 店小蜜升级 Triple 协议</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%BA%97%E5%B0%8F%E8%9C%9C%E5%8D%87%E7%BA%A7-triple-%E5%8D%8F%E8%AE%AE/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%BA%97%E5%B0%8F%E8%9C%9C%E5%8D%87%E7%BA%A7-triple-%E5%8D%8F%E8%AE%AE/</guid><description>
&lt;h1 id="前言">前言&lt;/h1>
&lt;p>阿里云-达摩院-云小蜜对话机器人产品基于深度机器学习技术、自然语言理解技术和对话管理技术,为企业提供多引擎、多渠道、多模态的对话机器人服务。17年云小蜜对话机器人在公共云开始公测,同期在混合云场景也不断拓展。为了同时保证公共云、混合云发版效率和稳定性,权衡再三我们采用了1-2个月一个大版本迭代。
经过几年发展,为了更好支撑业务发展,架构升级、重构总是一个绕不过去的坎,为了保证稳定性每次公共云发版研发同学都要做两件事:&lt;/p>
&lt;pre>&lt;code>1. 梳理各个模块相较线上版本接口依赖变化情况,决定十几个应用的上线顺序、每批次发布比例;
2. 模拟演练上述1产出的发布顺序,保证后端服务平滑升级,客户无感知;
&lt;/code>&lt;/pre>
&lt;p>上述 1、2 动作每次都需要 2-3 周左右的时间梳理、集中演练,但是也只能保证开放的PaaS API平滑更新;&lt;/p>
&lt;p>控制台服务因为需要前端、API、后端保持版本一致才能做到体验无损(如果每次迭代统一升级API版本开发、协同成本又会非常大),权衡之下之前都是流量低谷期上线,尽量缩短发布时间,避免部分控制台模块偶发报错带来业务问题。针对上面问题,很早之前就考虑过用蓝绿发布、灰度等手段解决,但是无奈之前对话机器人在阿里云内部业务区域,该不再允许普通云产品扩容,没有冗余的机器,流量治理完全没法做。&lt;/p>
&lt;h1 id="迁移阿里云云上">迁移阿里云云上&lt;/h1>
&lt;p>带着上面的问题,终于迎来的 2021 年 9 月份,云小蜜将业务迁移至阿里云云上。&lt;/p>
&lt;h2 id="dubbo3-的实践">Dubbo3 的实践&lt;/h2>
&lt;p>“当时印象最深的就是这张图,虽然当时不知道中间件团队具体要做什么事情,但是记住了两个关键词:三位一体、红利。没想到在2021年底,真真切切享受到了这个红利。”&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/yunxiaomi-1.png" alt="image1">&lt;/p>
&lt;p>云小蜜使用的是集团内部的HSF服务框架,需要迁移至阿里云云上,并且存在阿里云云上与阿里内部业务域的互通、互相治理的诉求。云小蜜的公共服务部署在公有云VPC,部分依赖的数据服务部署在内部,内部与云上服务存在RPC互调的诉求,其实属于混合云的典型场景。
简单整理了下他们的核心诉求,概括起来有以下三点吧:希望尽可能采用开源方案,方便后续业务推广;在网络通信层面需要保障安全性;对于业务升级改造来说需要做到低成本。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/yunxiaomi-2.png" alt="image2">&lt;/p>
&lt;p>在此场景下,经过许多讨论与探索,方案也敲定了下来&lt;/p>
&lt;ul>
&lt;li>全链路升级至开源 Dubbo3.0,云原生网关默认支持Dubbo3.0,实现透明转发,网关转发RT小于1ms&lt;/li>
&lt;li>利用 Dubbo3.0 支持HTTP2特性,云原生网关之间采用 mTLS 保障安全&lt;/li>
&lt;li>利用云原生网关默认支持多种注册中心的能力,实现跨域服务发现对用户透明,业务侧无需做任何额外改动&lt;/li>
&lt;li>业务侧升级SDK到支持 Dubbo3.0,配置发布 Triple 服务即可,无需额外改动&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>解决了互通、服务注册发现的问题之后,就是开始看如何进行服务治理方案了&lt;/strong>&lt;/p>
&lt;h1 id="阿里云云上流量治理">阿里云云上流量治理&lt;/h1>
&lt;p>迁移至阿里云云上之后,流量控制方案有非常多,比如集团内部的全链路方案、集团内单元化方案等等。&lt;/p>
&lt;h2 id="设计目标和原则">设计目标和原则&lt;/h2>
&lt;ol>
&lt;li>要引入一套流量隔离方案,上线过程中,新、旧两个版本服务同时存在时,流量能保证在同一个版本的“集群”里流转,这样就能解决重构带来的内部接口不兼容问题。&lt;/li>
&lt;li>要解决上线过程中控制台的平滑性问题,避免前端、后端、API更新不一致带来的问题。&lt;/li>
&lt;li>无上线需求的应用,可以不参与上线。&lt;/li>
&lt;li>资源消耗要尽量少,毕竟做产品最终还是要考虑成本和利润。&lt;/li>
&lt;/ol>
&lt;h2 id="方案选型">方案选型&lt;/h2>
&lt;ol>
&lt;li>集团内部的全链路方案:目前不支持阿里云云上&lt;/li>
&lt;li>集团内单元化方案:主要解决业务规模、容灾等问题,和我们碰到的问题不一样&lt;/li>
&lt;li>搭建独立集群,版本迭代时切集群:成本太大&lt;/li>
&lt;li>自建:在同一个集群隔离新、老服务,保证同一个用户的流量只在同版本服务内流转&lt;/li>
&lt;/ol>
&lt;p>以RPC为例:&lt;/p>
&lt;ul>
&lt;li>方案一:通过开发保证,当接口不兼容升级时,强制要求升级HSF version,并行提供两个版本的服务; 缺点是一个服务变更,关联使用方都要变更,协同成本特别大,并且为了保持平滑,新老接口要同时提供服务,维护成本也比较高&lt;/li>
&lt;li>方案二:给服务(机器)按版本打标,通过RPC框架的路由规则,保证流量优先在同版本内流转&lt;/li>
&lt;/ul>
&lt;h2 id="全链路灰度方案">全链路灰度方案&lt;/h2>
&lt;p>就当1、2、3、4都觉得不完美,一边调研一边准备自建方案5的时候,兜兜绕绕拿到了阿里云 MSE 微服务治理团队&lt;a href="https://yuque.antfin.com/docs/share/a8df43ac-3a3b-4af4-a443-472828884a5d?#">《20分钟获得同款企业级全链路灰度能力》&lt;/a>,方案中思路和准备自建的思路完全一致,也是利用了RPC框架的路由策略实现的流量治理,并且实现了产品化(微服务引擎-微服务治理中心),同时,聊了两次后得到几个“支持”,以及几个“后续可以支持”后,好像很多事情变得简单了&amp;hellip;&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/yunxiaomi-3.png" alt="image3">&lt;/p>
&lt;p>从上图可以看到,各个应用均需要搭建基线(base)环境和灰度(gray)环境,除了流量入口-业务网关以外,下游各个业务模块按需部署灰度(gray)环境,如果某次上线某模块没有变更则无需部署。&lt;/p>
&lt;h3 id="各个中间件的治理方案">各个中间件的治理方案&lt;/h3>
&lt;ol>
&lt;li>Mysql、ElasticSearch:持久化或半持久化数据,由业务模块自身保证数据结构兼容升级;&lt;/li>
&lt;li>Redis:由于对话产品会有多轮问答场景,问答上下文是在Redis里,如果不兼容则上线会导致会话过程中的C端用户受影响,因此目前Redis由业务模块自身保证数据结构兼容升级;&lt;/li>
&lt;li>配置中心:基线(base)环境、灰度(gray)环境维护两套全量配置会带来较大工作量,为了避免人工保证数据一致性成本,基线(base)环境监听dataId,灰度(gray)环境监听gray.dataId如果未配置gray.dataId则自动监听dataId;(云小蜜因为在18年做混合云项目为了保证混合云、公共云使用一套业务代码,建立了中间件适配层,本能力是在适配层实现)&lt;/li>
&lt;li>RPC服务:使用阿里云 one agent 基于Java Agent技术利用Dubbo框架的路由规则实现,无需修改业务代码;&lt;/li>
&lt;/ol>
&lt;p>应用只需要加一点配置:&lt;/p>
&lt;ul>
&lt;li>1)linux环境变量
alicloud.service.tag=gray标识灰度,基线无需打标
profiler.micro.service.tag.trace.enable=true标识经过该机器的流量,如果没有标签则自动染上和机器相同的标签,并向后透传&lt;/li>
&lt;li>2)JVM参数,标识开启MSE微服务流量治理能力** SERVICE_OPTS=&lt;strong>&amp;quot;$&lt;/strong>{SERVICE_OPTS}** -Dmse.enable=true&amp;quot;**&lt;/li>
&lt;/ul>
&lt;h3 id="流量管理方案">流量管理方案&lt;/h3>
&lt;p>流量的分发模块决定流量治理的粒度和管理的灵活程度。&lt;/p>
&lt;p>对话机器人产品需要灰度发布、蓝绿发布目前分别用下面两种方案实现:&lt;/p>
&lt;ol>
&lt;li>灰度发布:
部分应用单独更新,使用POP的灰度引流机制,该机制支持按百分比、UID的策略引流到灰度环境&lt;/li>
&lt;li>蓝绿发布:
&lt;ul>
&lt;li>1)部署灰度(gray)集群并测试:测试账号流量在灰度(gray)集群,其他账号流量在基线(base)集群&lt;/li>
&lt;li>2)线上版本更新:所有账号流量在灰度(gray)集群&lt;/li>
&lt;li>3)部署基线(base)集群并测试:测试账号流量在基线(base)集群,其他账号流量在灰度(gray)集群&lt;/li>
&lt;li>4)流量回切到基线(base)集群并缩容灰度(gray)环境:所有账号流量在基线(base)集群&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h2 id="全链路落地效果">全链路落地效果&lt;/h2>
&lt;p>上线后第一次发布的效果:“目前各个模块新版本的代码已经完成上线,含发布、功能回归一共大约花费2.5小时,相较之前每次上线到凌晨有很大提升。”
MSE 微服务治理全链路灰度方案满足了云小蜜业务在高速发展情况下快速迭代和小心验证的诉求,通过JavaAgent技术帮助云小蜜快速落地了企业级全链路灰度能力。
流量治理随着业务发展会有更多的需求,下一步,我们也会不断和微服务治理产品团队,扩充此解决方案的能力和使用场景,比如:rocketmq、schedulerx的灰度治理能力。&lt;/p>
&lt;h2 id="更多的微服务治理能力">更多的微服务治理能力&lt;/h2>
&lt;p>使用 MSE 服务治理后,发现还有更多开箱即用的治理能力,能够大大提升研发的效率。包含服务查询、服务契约、服务测试等等。这里要特别提一下就是云上的服务测试,服务测试即为用户提供一个云上私网 Postman ,让我们这边能够轻松调用自己的服务。我们可以忽略感知云上复杂的网络拓扑结构,无需关系服务的协议,无需自建测试工具,只需要通过控制台即可实现服务调用。支持 Dubbo 3.0 框架,以及 Dubbo 3.0 主流的 Triple 协议。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/yunxiaomi-4.png" alt="image4">&lt;/p>
&lt;h1 id="结束语">结束语&lt;/h1>
&lt;p>最终云小蜜对话机器人团队成功落地了全链路灰度功能,解决了困扰团队许久的发布效率问题。在这个过程中我们做了将部分业务迁移至阿里云云上、服务框架升级至Dubbo3.0、选择MSE微服务治理能力等等一次次新的选择与尝试。“世上本没有路,走的人多了便成了路”。经过我们工程师一次又一次的探索与实践,能够为更多的同学沉淀出一个个最佳实践。我相信这些最佳实践将会如大海中璀璨的明珠般,经过生产实践与时间的打磨将会变得更加熠熠生辉。&lt;/p></description></item><item><title>Blog: 瓜子二手车 Dubbo 实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E7%93%9C%E5%AD%90%E4%BA%8C%E6%89%8B%E8%BD%A6-dubbo-%E5%AE%9E%E8%B7%B5/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E7%93%9C%E5%AD%90%E4%BA%8C%E6%89%8B%E8%BD%A6-dubbo-%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;h2 id="前言">前言&lt;/h2>
&lt;p>  随着瓜子业务的不断发展,系统规模在逐渐扩大,目前在瓜子的私有云上已经运行着数百个dubbo应用,上千个dubbo实例。瓜子各部门业务迅速发展,版本没有来得及统一,各个部门都有自己的用法。随着第二机房的建设,dubbo版本统一的需求变得越发迫切。几个月前,公司发生了一次与dubbo相关的生产事故,成为了公司dubbo版本升级的诱因。&lt;/p>
&lt;p>  接下来,我会从这次事故开始,讲讲我们这段时间所做的dubbo版本升级的历程以及dubbo后续多机房的方案。&lt;/p>
&lt;h2 id="一ephermal节点未及时删除导致provider不能恢复注册的问题修复">一、Ephermal节点未及时删除导致provider不能恢复注册的问题修复&lt;/h2>
&lt;h3 id="事故背景">事故背景&lt;/h3>
&lt;p>  在生产环境,瓜子内部各业务线共用一套zookeeper集群作为dubbo的注册中心。2019年9月份,机房的一台交换机发生故障,导致zookeeper集群出现了几分钟的网络波动。在zookeeper集群恢复后,正常情况下dubbo的provider应该会很快重新注册到zookeeper上,但有一小部分的provider很长一段时间没有重新注册到zookeeper上,直到手动重启应用后才恢复注册。&lt;/p>
&lt;h3 id="排查过程">排查过程&lt;/h3>
&lt;p>  首先,我们统计了出现这种现象的dubbo服务的版本分布情况,发现在大多数的dubbo版本中都存在这种问题,且发生问题的服务比例相对较低,在github中我们也未找到相关问题的issues。因此,推断这是一个尚未修复的且在网络波动情况的场景下偶现的问题。&lt;/p>
&lt;p>  接着,我们便将出现问题的应用日志、zookeeper日志与dubbo代码逻辑进行相互印证。在应用日志中,应用重连zookeeper成功后provider立刻进行了重新注册,之后便没有任何日志打印。而在zookeeper日志中,注册节点被删除后,并没有重新创建注册节点。对应到dubbo的代码中,只有在&lt;code>FailbackRegistry.register(url)&lt;/code>的&lt;code>doRegister(url)&lt;/code>执行成功或线程被挂起的情况下,才能与日志中的情况相吻合。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">register&lt;/span>&lt;span style="color:#719e07">(&lt;/span>URL url&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>&lt;span style="color:#719e07">.&lt;/span>register&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> failedRegistered&lt;span style="color:#719e07">.&lt;/span>remove&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> failedUnregistered&lt;span style="color:#719e07">.&lt;/span>remove&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Sending a registration request to the server side
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> doRegister&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">catch&lt;/span> &lt;span style="color:#719e07">(&lt;/span>Exception e&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Throwable t &lt;span style="color:#719e07">=&lt;/span> e&lt;span style="color:#719e07">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// If the startup detection is opened, the Exception is thrown directly.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> &lt;span style="color:#dc322f">boolean&lt;/span> check &lt;span style="color:#719e07">=&lt;/span> getUrl&lt;span style="color:#719e07">().&lt;/span>getParameter&lt;span style="color:#719e07">(&lt;/span>Constants&lt;span style="color:#719e07">.&lt;/span>CHECK_KEY&lt;span style="color:#719e07">,&lt;/span> &lt;span style="color:#cb4b16">true&lt;/span>&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;amp;&amp;amp;&lt;/span> url&lt;span style="color:#719e07">.&lt;/span>getParameter&lt;span style="color:#719e07">(&lt;/span>Constants&lt;span style="color:#719e07">.&lt;/span>CHECK_KEY&lt;span style="color:#719e07">,&lt;/span> &lt;span style="color:#cb4b16">true&lt;/span>&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#719e07">!&lt;/span>Constants&lt;span style="color:#719e07">.&lt;/span>CONSUMER_PROTOCOL&lt;span style="color:#719e07">.&lt;/span>equals&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">.&lt;/span>getProtocol&lt;span style="color:#719e07">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">boolean&lt;/span> skipFailback &lt;span style="color:#719e07">=&lt;/span> t &lt;span style="color:#719e07">instanceof&lt;/span> SkipFailbackWrapperException&lt;span style="color:#719e07">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>check &lt;span style="color:#719e07">||&lt;/span> skipFailback&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>skipFailback&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t &lt;span style="color:#719e07">=&lt;/span> t&lt;span style="color:#719e07">.&lt;/span>getCause&lt;span style="color:#719e07">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException&lt;span style="color:#719e07">(&lt;/span>&lt;span style="color:#2aa198">&amp;#34;Failed to register &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> url &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; to registry &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> getUrl&lt;span style="color:#719e07">().&lt;/span>getAddress&lt;span style="color:#719e07">()&lt;/span> &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, cause: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t&lt;span style="color:#719e07">.&lt;/span>getMessage&lt;span style="color:#719e07">(),&lt;/span> t&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">else&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger&lt;span style="color:#719e07">.&lt;/span>error&lt;span style="color:#719e07">(&lt;/span>&lt;span style="color:#2aa198">&amp;#34;Failed to register &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> url &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, waiting for retry, cause: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t&lt;span style="color:#719e07">.&lt;/span>getMessage&lt;span style="color:#719e07">(),&lt;/span> t&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Record a failed registration request to a failed list, retry regularly
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> failedRegistered&lt;span style="color:#719e07">.&lt;/span>add&lt;span style="color:#719e07">(&lt;/span>url&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>  在继续排查问题前,我们先普及下这些概念:dubbo默认使用curator作为zookeeper的客户端,curator与zookeeper是通过session维持连接的。当curator重连zookeeper时,若session未过期,则继续使用原session进行连接;若session已过期,则创建新session重新连接。而ephemeral节点与session是绑定的关系,在session过期后,会删除此session下的ephemeral节点。&lt;/p>
&lt;p>  继续对&lt;code>doRegister(url)&lt;/code>的代码进行进一步排查,我们发现在&lt;code>CuratorZookeeperClient.createEphemeral(path)&lt;/code>方法中有这么一段逻辑:在&lt;code>createEphemeral(path)&lt;/code>捕获了&lt;code>NodeExistsException&lt;/code>,创建ephemeral节点时,若此节点已存在,则认为ephemeral节点创建成功。这段逻辑初看起来并没有什么问题,且在以下两种常见的场景下表现正常:&lt;/p>
&lt;ol>
&lt;li>Session未过期,创建Ephemeral节点时原节点仍存在,不需要重新创建&lt;/li>
&lt;li>Session已过期,创建Ephemeral节点时原节点已被zookeeper删除,创建成功&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">createEphemeral&lt;/span>&lt;span style="color:#719e07">(&lt;/span>String path&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#719e07">.&lt;/span>create&lt;span style="color:#719e07">().&lt;/span>withMode&lt;span style="color:#719e07">(&lt;/span>CreateMode&lt;span style="color:#719e07">.&lt;/span>EPHEMERAL&lt;span style="color:#719e07">).&lt;/span>forPath&lt;span style="color:#719e07">(&lt;/span>path&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">catch&lt;/span> &lt;span style="color:#719e07">(&lt;/span>NodeExistsException e&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">catch&lt;/span> &lt;span style="color:#719e07">(&lt;/span>Exception e&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException&lt;span style="color:#719e07">(&lt;/span>e&lt;span style="color:#719e07">.&lt;/span>getMessage&lt;span style="color:#719e07">(),&lt;/span> e&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>  但是实际上还有一种极端场景,&lt;strong>zookeeper的Session过期与删除Ephemeral节点不是原子性的&lt;/strong>,也就是说客户端在得到Session过期的消息时,Session对应的Ephemeral节点可能还未被zookeeper删除。此时dubbo去创建Ephemeral节点,发现原节点仍存在,故不重新创建。待Ephemeral节点被zookeeper删除后,便会出现dubbo认为重新注册成功,但实际未成功的情况,也就是我们在生产环境遇到的问题。&lt;/p>
&lt;p>  此时,问题的根源已被定位。定位问题之后,我们与dubbo社区交流,发现考拉的同学也遇到过同样的问题,更确定了这个原因。&lt;/p>
&lt;h3 id="问题的复现与修复">问题的复现与修复&lt;/h3>
&lt;p>  定位到问题之后,我们便开始尝试本地复现。由于zookeeper的Session过期但Ephemeral节点未被删除的场景直接模拟比较困难,我们通过修改zookeeper源码,在Session过期与删除Ephemeral节点的逻辑中增加了一段休眠时间,间接模拟出这种极端场景,并在本地复现了此问题。&lt;/p>
&lt;p>  在排查问题的过程中,我们发现kafka的旧版本在使用zookeeper时也遇到过类似的问题,并参考kafka关于此问题的修复方案,确定了dubbo的修复方案。在创建Ephemeral节点捕获到&lt;code>NodeExistsException&lt;/code>时进行判断,若Ephemeral节点的SessionId与当前客户端的SessionId不同,则删除并重建Ephemeral节点。在内部修复并验证通过后,我们向社区提交了issues及pr。&lt;/p>
&lt;p>  kafka类似问题issues:https://issues.apache.org/jira/browse/KAFKA-1387&lt;/p>
&lt;p>  dubbo注册恢复问题issues:https://github.com/apache/dubbo/issues/5125&lt;/p>
&lt;h2 id="二瓜子的dubbo升级历程">二、瓜子的dubbo升级历程&lt;/h2>
&lt;p>  上文中的问题修复方案已经确定,但我们显然不可能在每一个dubbo版本上都进行修复。在咨询了社区dubbo的推荐版本后,我们决定在dubbo2.7.3版本的基础上,开发内部版本修复来这个问题。并借这个机会,开始推动公司dubbo版本的统一升级工作。&lt;/p>
&lt;h3 id="为什么要统一dubbo版本">为什么要统一dubbo版本&lt;/h3>
&lt;ol>
&lt;li>统一dubbo版本后,我们可以在此版本上内部紧急修复一些dubbo问题(如上文的dubbo注册故障恢复失效问题)。&lt;/li>
&lt;li>瓜子目前正在进行第二机房的建设,部分dubbo服务也在逐渐往第二机房迁移。统一dubbo版本,也是为dubbo的多机房做铺垫。&lt;/li>
&lt;li>有利于我们后续对dubbo服务的统一管控。&lt;/li>
&lt;li>dubbo社区目前的发展方向与我们公司现阶段对dubbo的一些诉求相吻合,如支持gRPC、云原生等。&lt;/li>
&lt;/ol>
&lt;h3 id="为什么选择dubbo273">为什么选择dubbo2.7.3&lt;/h3>
&lt;ol>
&lt;li>在我们之前,携程与dubbo社区合作进行了携程dubbo内部版本的升级,并在社区2.7.3版本上修复了很多兼容性问题。感谢携程的同学帮我们踩坑~&lt;/li>
&lt;li>dubbo2.7.3版本在当时虽然是最新的版本,但已经发布了2个月的时间,从社区issues反馈来看,dubbo2.7.3相对dubbo2.7之前的几个版本,在兼容性方面要好很多。&lt;/li>
&lt;li>我们也咨询了dubbo社区的同学,推荐升级版本为2.7.3。&lt;/li>
&lt;/ol>
&lt;h3 id="内部版本定位">内部版本定位&lt;/h3>
&lt;p>  基于社区dubbo2.7.3版本开发的dubbo内部版本属于过渡性质的版本,目的是为了修复线上provider不能恢复注册的问题,以及一些社区dubbo2.7.3的兼容性问题。瓜子的dubbo最终还是要跟随社区的版本,而不是开发自已的内部功能。因此我们在dubbo内部版本中修复的所有问题均与社区保持了同步,以保证后续可以兼容升级到社区dubbo的更高版本。&lt;/p>
&lt;h3 id="兼容性验证与升级过程">兼容性验证与升级过程&lt;/h3>
&lt;p>  我们在向dubbo社区的同学咨询了版本升级方面的相关经验后,于9月下旬开始了dubbo版本的升级工作。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>初步兼容性验证&lt;/strong>
首先,我们梳理了一些需要验证的兼容性case,针对公司内部使用较多的dubbo版本,与dubbo2.7.3一一进行了兼容性验证。经验证,除dubboX外,dubbo2.7.3与其他dubbo版本均兼容。dubboX由于对dubbo协议进行了更改,与dubbo2.7.3不兼容。&lt;/li>
&lt;li>&lt;strong>生产环境兼容性验证&lt;/strong>
在初步验证兼容性通过后,我们与业务线合作,挑选了一些重要程度较低的项目,在生产环境对dubbo2.7.3与其他版本的兼容性进行了进一步验证。并在内部版本修复了一些兼容性问题。&lt;/li>
&lt;li>&lt;strong>推动公司dubbo版本升级&lt;/strong>
在10月初,完成了dubbo兼容性验证后,我们开始在各个业务线推动dubbo的升级工作。截止到12月初,已经有30%的dubbo服务的完成了版本升级。按照排期,预计于2020年3月底前完成公司dubbo版本的统一升级。&lt;/li>
&lt;/ol>
&lt;h3 id="兼容性问题汇总">兼容性问题汇总&lt;/h3>
&lt;p>  在推动升级dubbo2.7.3版本的过程整体上比较顺利,当然也遇到了一些兼容性问题:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>创建zookeeper节点时提示没有权限&lt;/strong>
dubbo配置文件中已经配置了zookeeper的用户名密码,但在创建zookeeper节点时却抛出&lt;code>KeeperErrorCode = NoAuth&lt;/code>的异常,这种情况分别对应两个兼容性问题:&lt;/p>
&lt;ul>
&lt;li>issues:https://github.com/apache/dubbo/issues/5076
dubbo在未配置配置中心时,默认使用注册中心作为配置中心。通过注册中心的配置信息初始化配置中心配置时,由于遗漏了用户名密码,导致此问题。&lt;/li>
&lt;li>issues:https://github.com/apache/dubbo/issues/4991
dubbo在建立与zookeeper的连接时会根据zookeeper的address复用之前已建立的连接。当多个注册中心使用同一个address,但权限不同时,就会出现&lt;code>NoAuth&lt;/code>的问题。
参考社区的pr,我们在内部版本进行了修复。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>curator版本兼容性问题&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>dubbo2.7.3与低版本的curator不兼容,因此我们默认将curator版本升级至4.2.0&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache.curator&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>curator-framework&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>4.2.0&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache.curator&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>curator-recipes&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>4.2.0&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>分布式调度框架elastic-job-lite强依赖低版本的curator,与dubbo2.7.3使用的curator版本不兼容,这给dubbo版本升级工作带来了一定阻塞。考虑到elastic-job-lite已经很久没有人进行维护,目前一些业务线计划将elastic-job-lite替换为其他的调度框架。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>openFeign与dubbo兼容性问题&lt;/strong>
issues: &lt;a href="https://github.com/apache/dubbo/issues/3990">https://github.com/apache/dubbo/issues/3990&lt;/a>
dubbo的ServiceBean监听spring的ContextRefreshedEvent,进行服务暴露。openFeign提前触发了ContextRefreshedEvent,此时ServiceBean还未完成初始化,于是就导致了应用启动异常。
参考社区的pr,我们在内部版本修复了此问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>RpcException兼容性问题&lt;/strong>
dubbo低版本consumer不能识别dubbo2.7版本provider抛出的&lt;code>org.apache.dubbo.rpc.RpcException&lt;/code>。因此,在consumer全部升级到2.7之前,不建议将provider的&lt;code>com.alibaba.dubbo.rpc.RpcException&lt;/code>改为&lt;code>org.apache.dubbo.rpc.RpcException&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>qos端口占用&lt;/strong>
dubbo2.7.3默认开启qos功能,导致一些混部在物理机的dubbo服务升级时出现qos端口占用问题。关闭qos功能后恢复。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>自定义扩展兼容性问题&lt;/strong>
业务线对于dubbo的自定义扩展比较少,因此在自定义扩展的兼容性方面暂时还没有遇到比较难处理的问题,基本上都是变更package导致的问题,由业务线自行修复。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>skywalking agent兼容性问题&lt;/strong>
我们项目中一般使用skywalking进行链路追踪,由于skywalking agent6.0的plugin不支持dubbo2.7,因此统一升级skywalking agent到6.1。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="三dubbo多机房方案">三、dubbo多机房方案&lt;/h2>
&lt;p>  瓜子目前正在进行第二机房的建设工作,dubbo多机房是第二机房建设中比较重要的一个话题。在dubbo版本统一的前提下,我们就能够更顺利的开展dubbo多机房相关的调研与开发工作。&lt;/p>
&lt;h3 id="初步方案">初步方案&lt;/h3>
&lt;p>  我们咨询了dubbo社区的建议,并结合瓜子云平台的现状,初步确定了dubbo多机房的方案。&lt;/p>
&lt;ol>
&lt;li>在每个机房内,部署一套独立的zookeeper集群。集群间信息不同步。这样就没有了zookeeper集群跨机房延迟与数据不同步的问题。&lt;/li>
&lt;li>dubbo服务注册时,仅注册到本机房的zookeeper集群;订阅时,同时订阅两个机房的zookeeper集群。&lt;/li>
&lt;li>实现同机房优先调用的路由逻辑。以减少跨机房调用导致的不必要网络延迟。&lt;/li>
&lt;/ol>
&lt;h3 id="同机房优先调用">同机房优先调用&lt;/h3>
&lt;p>  dubbo同机房优先调用的实现比较简单,相关逻辑如下:&lt;/p>
&lt;ol>
&lt;li>瓜子云平台默认将机房的标志信息注入容器的环境变量中。&lt;/li>
&lt;li>provider暴露服务时,读取环境变量中的机房标志信息,追加到待暴露服务的url中。&lt;/li>
&lt;li>consumer调用provider时,读取环境变量中的机房标志信息,根据路由策略优先调用具有相同标志信息的provider。&lt;/li>
&lt;/ol>
&lt;p>  针对以上逻辑,我们简单实现了dubbo通过环境变量进行路由的功能,并向社区提交了pr。
  dubbo通过环境变量路由pr: &lt;a href="https://github.com/apache/dubbo/pull/5348">https://github.com/apache/dubbo/pull/5348&lt;/a>&lt;/p></description></item><item><title>Blog: 小米与 Dubbo 社区的合作</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B0%8F%E7%B1%B3%E4%B8%8E-dubbo-%E7%A4%BE%E5%8C%BA%E7%9A%84%E5%90%88%E4%BD%9C/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B0%8F%E7%B1%B3%E4%B8%8E-dubbo-%E7%A4%BE%E5%8C%BA%E7%9A%84%E5%90%88%E4%BD%9C/</guid><description>
&lt;p>小米一直在积极拥抱开源社区并提交贡献,参与Dubbo3建设发布以来,在内部业务也积极推进升级工作,目前实例数已经升级到了一定的比例 。升级过程总体平稳,稳定性指标正常,性能提升明显,率先升级完成的应用更早拥有了mesh化的条件。从升级后的数据表现来看,Dubbo3改变以往接口粒度的注册发现方式为应用粒度的注册发现方式,这样带来了注册中心存储和运行的更稳定,降低运维成本;使用protobuf协议进行序列化与反序列化,性能和字节大小均提升数量级;完全兼容gprc,给小米这样多言语并存的服务环境带来了极大便利。&lt;/p>
&lt;p>Xiaomi is devoted to making continuous contribution to the open source community. Since the introduction of Dubbo3, internal projects are rapidly upgrading to the latest version of Dubbo. Currently, At present the numbers of instances has been upgrade to a certain proportion. Not only performance improvements have been seen, but services are also running smoothly with improvements in availability. Statistics provide proof that Dubbo’s switch from api-level discovery to application-level discovery has improved the availability and reliability of service discovery, which leads to lower operations cost. In addition, using ProtoBuf for serialization and deserialization has reduced data exchange size. Lastly, full compatibility with grpc provides convenience to Xiaomi’s multi-language development environment.&lt;/p>
&lt;p>Dubbo3 基于 Dubbo2 演进而来,Dubbo3 在云原生基础设施适配、服务注册发现、面向下一代协议设计等几大方向上进行了全面升级。并且往 3.0 版本的升级过程将会是完全透明的,用户无需做任何业务改造,就可以直接升级到 Dubbo 3.0。
下面从云原生适配、全新服务发现模型、通信协议、升级兼容四个方面详细介绍。&lt;/p>
&lt;p>Having evolved from Dubbo2, Dubbo3 is a major upgrade in several areas including, Cloud Native adaptation, service discovery, communication protocols. Furthermore, upgrading to version 3.0 requires no changes in application code. The following is a detailed introduction to Dubbo3’s features.&lt;/p>
&lt;h3 id="云原生适配--cloud-native-adaptation">云原生适配 Cloud Native Adaptation&lt;/h3>
&lt;p>Dubbo3从理念到设计再到实现最大的变革之一在于全面遵循云原生环境,做到了面向未来,为了达到这个目标dubbo本身做了相当重要的取舍。
在“取”这个层面,Dubbo3众多核心组件已经面向云原生升级,支持 Kubernetes 平台调度,实现了服务生命周期与容器生命周期的对齐,Serverless、Native Image等机制都在计划之中。&lt;/p>
&lt;p>在“舍”这个层面,Dubbo3割舍了以往要求开发人员遵守并熟知的Dubbo启动、销毁、注册等生命周期事件,Dubbo3自身设配了Kubernetes基础设施定义的生命周期事件(probe),并且将服务的定义与注册下沉到了Kubernetes Service,重新划定了dubbo和k8s基础设施的边界。&lt;/p>
&lt;p>To be future proof, the design and development of Dubbo3 has fully adapted Cloud Native. To meet this goal, Dubbo has made some trade-offs.Several core components of Dubbo3 support Kubernetes. In particular, Dubbo3 implements Kubernetes service and container life-cycle. Serverless and native image support will be release in the future.&lt;/p>
&lt;p>To support Kubernetes, Dubbo3 places service registration and discovery down to the Kubernetes Service layer, thus reestablishing the boundary between Dubbo and Kubernetes. However, this requires deprecating Dubbo’s own service discovery events.&lt;/p>
&lt;h3 id="全新服务发现模型--new-service-discovery-model">全新服务发现模型 New Service Discovery Model&lt;/h3>
&lt;p>Dubbo以往版本与Spring Cloud、gRPC等同属主流的服务框架进行服务发现的粒度不一致,Dubbo选择了基于更细粒度的接口来进行服务发现,Dubbo3.x进行了服务发现机制的对齐,即以应用粒度来进行服务发现,应用粒度的机制也带来了几点好处:&lt;/p>
&lt;ol>
&lt;li>打通与其他异构微服务体系的地址互发现障碍,这一点对于小米这样的多语种多框架并存的技术组织非常重要。&lt;/li>
&lt;li>提升了 Dubbo3 在大规模集群实践中的性能与稳定性。新模型可大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗近一半,降低注册中心集群的存储与推送压力一半以上, Dubbo 可支持集群规模步入百万实例层次。&lt;/li>
&lt;/ol>
&lt;p>Previous versions of Dubbo differs from other mainstream service discovery middle-ware such as Spring Cloud and gRPC in its service discovery granularity. In the past Dubbo discovers services at the API level. Dubbo3, however, utilizes application level service discovery. This provides the following benefits.&lt;/p>
&lt;ol>
&lt;li>Eliminates incompatibility issues with other service discovery platforms, which is crucial since Xiaomi has diverse languages and development frameworks.&lt;/li>
&lt;li>The new service discovery model improves resource utilization, lowers Dubbo address’s single machine memory usage, lowers service discover cluster’s load.&lt;/li>
&lt;/ol>
&lt;h3 id="全新rpc-通信协议--new-rpc-communication-protocal">全新RPC 通信协议 New RPC Communication Protocal&lt;/h3>
&lt;p>定义了全新的 RPC 通信协议 – Triple,它是基于 HTTP/2 上构建的 RPC 协议。 使用 Triple 协议,用户将获得以下能力:&lt;/p>
&lt;ol>
&lt;li>完全兼容gRPC,能够更友好的支持跨语言跨框架的微服务进行互通。&lt;/li>
&lt;li>支持Protobuf进行序列化与反序列化,性能和字节大小均提升数量级。&lt;/li>
&lt;/ol>
&lt;p>Introduction of a new RPC communication protocol based on HTTP/2 called Triple. Using Triple has the following benefits.&lt;/p>
&lt;ol>
&lt;li>Complete compatibility with gRPC.&lt;/li>
&lt;li>Protobuf support for serialization and deserialization.&lt;/li>
&lt;/ol>
&lt;h3 id="升级与兼容性--upgrade-and-backwards-compatibility">升级与兼容性 Upgrade and Backwards Compatibility&lt;/h3>
&lt;p>对业务而言,在保证兼容以往版本的前提下进行升级是最核心的问题,在 3.0 版本的设计与开发之初,就定下了兼容老版本 Dubbo 用户(2.5、2.6、2.7)的目标。因此,往 3.0 版本的升级过程将会是完全透明的,用户无需做任何业务改造,升级 3.x 后的框架行为将保持与 2.x 版本完全一致。&lt;/p>
&lt;p>但也要注意,透明升级仅仅是通往 3.0 的第一步,因为 “框架行为保持一致” 也就意味着用户将无法体验到 3.0 的新特性。如果要启用 3.0 带来的新特性,用户则需要进行一定的改造,这个过程称为迁移,这是一个按需开启的过程。
因此,对老用户而言,有两条不同的迁移路径:&lt;/p>
&lt;ol>
&lt;li>分两步走,先以兼容模式推动业务升级到 3.0 版本(无需改造),之后在某些时机按需启用新特性(按需改造);&lt;/li>
&lt;li>升级与迁移同步完成,在业务升级到 3.0 版本的同时,完成改造并启用新特性;&lt;/li>
&lt;/ol>
&lt;p>第一种方式更安全,第二种方式更彻底,业务可根据自身的情况来进行评判选择。&lt;/p>
&lt;p>For production systems, upgrading a dependency while maintaining backward compatibility is challenging. Supporting users of older versions of Dubbo (2.5, 2.6, 2,7) is a goal of Dubbo3’s design and development. Thus, upgrading to Dubbo3 is painless. No changes are required to be made to existing production systems. However to use Dubbo3’s new features, additional changes are needed to existing code. Thus, there are two suggested upgrade paths.&lt;/p>
&lt;ol>
&lt;li>Upgrade to Dubbo3 but do not use Dubbo3’s new features. This path requires no code changes.&lt;/li>
&lt;li>Upgrade to Dubbo3 while making additional changes to support the new features.&lt;/li>
&lt;/ol>
&lt;h3 id="建议">建议&lt;/h3>
&lt;ol>
&lt;li>dubbo3已经和云原生做了深度适配,建议后续能够和istio等service mesh框架进行更多的衔接打通,方便dubbo用户更简单的走向mesh化之路;&lt;/li>
&lt;li>建议在调用方和服务方调用链路上增加更多的可选可观测点;&lt;/li>
&lt;/ol>
&lt;p>Suggestions&lt;/p>
&lt;ol>
&lt;li>Since Dubbo3 is closely compatible with Cloud Native, further work can be done to enhance Dubbo’s support of istio and other service mesh frameworks to speed up Dubbo users’ adaption of service mesh.&lt;/li>
&lt;li>Add more performance metrics to monitor Dubbo consumers and providers.&lt;/li>
&lt;/ol>
&lt;h3 id="作者">作者&lt;/h3>
&lt;ul>
&lt;li>张志勇&lt;/li>
&lt;li>张平&lt;/li>
&lt;li>许铮&lt;/li>
&lt;/ul></description></item><item><title>Blog: 中伦网络 Dubbo3 升级实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E4%B8%AD%E4%BC%A6%E7%BD%91%E7%BB%9C-dubbo3-%E5%8D%87%E7%BA%A7%E5%AE%9E%E8%B7%B5/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E4%B8%AD%E4%BC%A6%E7%BD%91%E7%BB%9C-dubbo3-%E5%8D%87%E7%BA%A7%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>中伦网络在 2022 年完成了服务框架从 Dubbo2 到 Dubbo3 的全站升级,深度使用了应用级服务发现、Kubernetes 原生服务部署、服务治理等核心能力。来自中仑网络的技术负责人来彬彬对整个 Dubbo3 的选型、升级过程及收益等做了深入总结。&lt;/p>
&lt;p>值得一提的是近期 &lt;a href="https://dubbo.apache.org/zh-cn/">Dubbo3 官网文档&lt;/a> 整体有了本质的提升,并且社区承诺短期内文档还会投入大量精力完善文档,这点对于 Dubbo3 的使用和用户信心提升非常重要。&lt;/p>
&lt;h3 id="一公司业务与技术架构简介">一、公司业务与技术架构简介&lt;/h3>
&lt;p>&lt;a href="https://www.zhonglunnet.com/guanyu.html">苏州中仑网络科技有限公司&lt;/a>是一家“专注零售门店增收服务”的公司,一直以“解决中小零售门店经营难的问题”为初心,致力于为零售商户提供门店运营一体化解决方案,帮助零售门店实现增收。中仑网络以零售技术为核心,为零售商户打造出集收银系统、中仑掌柜、微商城、汇邻生活平台、大数据平台、移动支付、智慧农贸、汇邻门店运营服务等为一体的新零售生态体系,实现线上线下全方位融合,为零售商家赋能增收。技术团队在构建之初选取Dubbo 2.5.3+Zookeeper版本构建公司微服务基座支撑公司业务发展,后期同阿里云深度合作整体迁移使用阿里云,使用云原生基础设施ACK(Kubernetes)+MSE(Zookeeper)+Dubbo+PolarDB等构建,实现可动态缩扩容的服务能力。
伴随合作商扩展3000+,市场遍及300+城市,零售商户30万+,服务覆盖餐饮、茶饮、服装、母婴、烘焙、生鲜、商超、美业、美妆、宠物等多个行业。伴随着领域拓宽、商户量快速增长上升,系统数量和部署节点也迎来了暴增,随之在系统可用性上受到较大挑战:微服务治理能力、微服务地址注册发现,Kubernetes平台服务的无损上下线顺滑度上问题与挑战越来越多。架构图见图一。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zhonglunwangluo-1.png" alt="image1">&lt;/p>
&lt;p>图一&lt;/p>
&lt;h3 id="二dubbo3-升级总结">二、Dubbo3 升级总结&lt;/h3>
&lt;p>在升级微服务组件技术选型上主要考虑解决以前的痛点:服务治理能力、云原生友好性、服务注册发现,这几个制约业务发展的紧要问题。比较下来Dubbo3架构设计理念与我们较为契合,能较好的满足我们业务发展要求。&lt;/p>
&lt;h3 id="1服务治理能力">1、服务治理能力&lt;/h3>
&lt;p>Dubbo 3提供丰富的服务治理能力,可实现诸如服务发现、负载均衡、流量调度等服务治理诉求。在使用上我们有两种选择:一、使用Dubbo管理控制台管理配置、二、集成相关API能力到系统。同时Dubbo 扩展性较好,可以在很多功能点(见图二)去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。Dubbo SPI ( Service Provider Interface)将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。基于此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能,如我们在此基础上实现了基于生产和消费者过滤器Filter实现全链路自定义的链路监控;基于路由扩展标签路由方式进行测试环境的隔离方便快速多版本服务测试验证。实操上我们基于生产者注册服务时打标,如原系统A V1版本部署在fat环境上,现在为了测试V2版本,我们将V2版本打标tag=fat-v2;使用端在消费时指定Invocation Attachment 参数,inv.setAttachment(TAG_KEY, routeTag);基于此我们可以方便自测试,同时生产上我们也可以做简单的生产灰度运用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zhonglunwangluo-2.png" alt="image2">
图二&lt;/p>
&lt;h3 id="2云原生友好性">2、云原生友好性&lt;/h3>
&lt;p>Dubbo 在设计上遵循云原生微服务开发理念,微服务支持 Kubernetes平台调度,实现服务生命周期与容器生命周期的对齐,包括 Dubbo 的启动、销毁、服务注册等生命周期事件。中仑网络微服务管理使用的是MSE(Zookeeper),因而我们服务暴露使用需与之对齐。具体操作上我们自定义Startup 启动探针、 Liveness 存活探针、Readiness 就绪探针。项目的正常切换需要保障无损的上下线,在实施中无损上线相对于下线来说会更麻烦点,项目的发布上线过程大体会遵从如下流程:大致分成三个阶段,第一阶段升级少量(如 20% )的实例,并切换少量流量到新版本,完成这个阶段后先暂停升级。经过人工确认之后继续第二个阶段,升级更大比例(如 90% )的实例和流量,再次暂停等待人工确认。最后阶段将全量升级到新版本并验证完毕,从而完成整个发布过程。如果升级期间发现包括业务指标在内的任何异常,例如 CPU 或 memory 异常使用率升高或请求 500 日志过多等情况,可以快速回滚。因为我们使用的是MSE(Zookeeper)服务,dubbo服务自注册在应用启动过程暴露不受Kubernetes 生命周期的控制,出现项目未完全就绪部分服务可被提前可被访问问题。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zhonglunwangluo-3.png" alt="image3">
图三&lt;/p>
&lt;p>实施处理上我们主要利用Dubbo Qos指令,初始使用服务不暴露,在应用就绪后调用Qos online指令进行服务上线替换老节点,每次替换的节点数量基于发布策略来制定;下线过程针对需下线节点我们会先使用Qos指令进行下线offline操作等待应用执行完服务,从而进行优雅停机,从实践的效果来看能满足我们的生产需求。&lt;/p>
&lt;h3 id="3实例级别升级切换">3、实例级别升级切换&lt;/h3>
&lt;p>相比于 2.x 版本中的基于接口粒度的服务发现机制,3.x 引入了全新的基于应用粒度的服务发现机制,进一步提升了 Dubbo3 在大规模集群实践中的性能与稳定性。此次升级过程中我们也同步引入了配置中心与原数据中心,即将图四置灰部分启用&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zhonglunwangluo-4.png" alt="image4">
图四&lt;/p>
&lt;p>采用实例级别注册管理,一个应用N个服务,接口级时N服务需监听推送,应用级只关注单实例相关信息。同时引入元数据中心后极大降低接口配置数据信息,减少接口数据传输大小,相关职责配置也更加清晰。根据测试新模型大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗,大幅降低注册中心集群的存储与推送压力,上线后稳定性有较大的提升。&lt;/p>
&lt;h3 id="三总结与展望">三、总结与展望&lt;/h3>
&lt;p>在中仑网络Dubbo 2升级Dubbo 3的过程中我们也有过一些迟疑,如把接口级换成应用级还是混合注册;Dubbo 3.0新特性新技术在项目中引入的时机与范围。对公司来说大的升级意味风险和不可预知的问题,但同时也能为之带来资源利用率提升、基础功能的扩展与增强,作为技术人员我们需要反复谨慎评估与论证。现在我们已经完成切换所有的业务领域。&lt;/p>
&lt;h3 id="四dubbo-社区合作">四、Dubbo 社区合作&lt;/h3>
&lt;p>在这里再次感谢Dubbo社区人员的专业、高效,以及对中仑网络架构升级的大力支持,同时很荣幸能够成为一名社区的贡献者,感兴趣的同学可以&lt;strong>加入贡献者钉钉群:31982034&lt;/strong>。&lt;/p>
&lt;p>Dubbo 社区近期筹办了每周一次的微服务纯技术分享,讲解 Dubbo 使用、源码,同时涵盖众多云原生微服务知识,感兴趣的同学可扫码关注。&lt;/p></description></item><item><title>Blog: 平安健康的 Dubbo3 迁移历程</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B9%B3%E5%AE%89%E5%81%A5%E5%BA%B7%E7%9A%84-dubbo3-%E8%BF%81%E7%A7%BB%E5%8E%86%E7%A8%8B/</link><pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/15/%E5%B9%B3%E5%AE%89%E5%81%A5%E5%BA%B7%E7%9A%84-dubbo3-%E8%BF%81%E7%A7%BB%E5%8E%86%E7%A8%8B/</guid><description>
&lt;h1 id="1-背景">1 背景&lt;/h1>
&lt;p>我们公司从15年开始就使⽤dubbo作为微服务框架,当社区推出dubbo3时,我们也⽴刻跟进并做了深⼊调研,发现dubbo3 的应⽤/实例级服务注册和发现模式能够在一定程度上解决我们当前注册中⼼⾯临的压⼒,解决稳定性和安全性问题。同时dubbo3在服务治理上也做了升级,契合云原⽣架构,⽽且dubbo3能够向下兼容dubbo2,这也将降低升级的成本和⻛险。&lt;/p>
&lt;p>升级项目有了阶段性的进展,目前仍然在进行中。通过本⽂,我们对公司内部的Dubbo3 升级过程及收益等做了深⼊总结。&lt;/p>
&lt;h1 id="2-dubbo3-核功能介绍">2 Dubbo3 核⼼功能介绍&lt;/h1>
&lt;p>dubbo社区关于dubbo3的文档和资料越来越完善,以下是我们从社区引用的一些内容。&lt;/p>
&lt;h2 id="21-下一代云原生服务框架">2.1 下一代云原生服务框架&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-2.png" alt="pingan">&lt;/p>
&lt;p>Dubbo3被社区寄予厚望,将其视为下一代云原生服务框架打造,Dubbo3 提供的核心特性列表,主要包括四部分。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>全新服务发现模型&lt;/strong> 。应用粒度服务发现,面向云原生设计,适配基础设施与异构系统;性能与集群伸缩性大幅提升。&lt;/li>
&lt;li>**下一代 **** RPC **&lt;strong>协议&lt;/strong> &lt;strong>Triple&lt;/strong> 。基于 HTTP/2 的 Triple 协议,兼容 gRPC;网关穿透性强、多语言友好、支持 Reactive Stream。&lt;/li>
&lt;li>&lt;strong>统一流量治理模型&lt;/strong> 。面向云原生流量治理,SDK、Mesh、VM、Container 等统一治理规则;能够支持更丰富的流量治理场景。&lt;/li>
&lt;li>&lt;strong>Service Mesh&lt;/strong> 。在最新的3.1.0的版本中支持Sidecar Mesh 与 Proxyless Mesh,提供更多架构选择,降低迁移、落地成本。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-3.png" alt="pingan">&lt;/p>
&lt;p>首先是性能、资源利用率的提升。社区资料显示,升级 Dubbo3 的应用预期能实现单机内存 50% 的下降,对于越大规模的集群效果将越明显,Dubbo3 从架构上支持百万实例级别的集群横向扩展,同时依赖应用级服务发现、Triple协议等可以大大提供应用的服务治理效率和吞吐量。&lt;/p>
&lt;p>其次, Dubbo3 让业务架构升级变得更容易、更合理,尤其是RPC协议,在 2.x 版本中,web、移动端与后端的通信都要经过网关代理,完成协议转换、类型映射等工作,dubbo3的Triple 协议让这些变得更容易与自然;并通过流式通信模型满足更多的使用场景。&lt;/p>
&lt;p>最后,得益于 Dubbo3 的完善云原生解决方案,Dubbo3的mesh架构可以帮助业务屏蔽底层云原生基础设施细节,让业务更专注于业务,这也是mesh的最根本的优势。&lt;/p>
&lt;h2 id="22-应用级服务发现核心原理">2.2 应用级服务发现核心原理&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-4.png" alt="pingan">&lt;/p>
&lt;p>我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。 在这个过程中&lt;/p>
&lt;ul>
&lt;li>每个 Provider 通过特定的 key 向注册中心注册本机可访问地址;&lt;/li>
&lt;li>注册中心通过这个 key 对 provider 实例地址进行聚合;&lt;/li>
&lt;li>Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表;&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-5.png" alt="pingan">&lt;/p>
&lt;p>再来看一下Provider向注册中心注册的 URL 地址的详细格式,这里把 URL 地址数据划分成了几份:&lt;/p>
&lt;ul>
&lt;li>首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体。&lt;/li>
&lt;li>其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息。&lt;/li>
&lt;li>下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。&lt;/li>
&lt;li>最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。&lt;/li>
&lt;/ul>
&lt;p>结合以上对于 Dubbo2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,可以得出这么几条结论:&lt;/p>
&lt;ul>
&lt;li>第一,地址发现聚合的 key 就是 RPC 粒度的服务。&lt;/li>
&lt;li>第二,注册中心同步的数据不止包含地址,还包含了各种元数据以及配置。&lt;/li>
&lt;li>得益于 1 与 2,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力。&lt;/li>
&lt;/ul>
&lt;p>这就是一直以来 Dubbo2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。&lt;/p>
&lt;p>面对这样的地址数量级放大的问题,在 Dubbo3 架构下,社区认真思考了两个问题:&lt;/p>
&lt;ul>
&lt;li>如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo3 能支撑更大规模集群水平扩容?&lt;/li>
&lt;li>如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通?&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-6.png" alt="pingan">&lt;/p>
&lt;p>最终,社区给出的方案也是非常巧妙和经典。Dubbo3 的应用级服务发现方案设计的基本思路是:地址发现链路上的聚合元素也就是之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来,与kubernetes和spring cloud的服务注册发现处于同一粒度,能够平滑打通;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。 经过上述调整,应用级别服务发现在保持接口级地址模型易用性的同时,实现了地址单条数据大小和总数量的下降。&lt;/p>
&lt;p>元数据、配置数据以及自定义数据等通过元数据中心或者MetadataService进行同步,且将所有的数据生成一个metadata revision, metadata revision相同则认为元数据等信息相同,通过这种方式来降低元数据中心或MetadataService的访问频次。&lt;/p>
&lt;h1 id="3-前期调研">3 前期调研&lt;/h1>
&lt;p>了解了 Dubbo3 的核心功能以及应用级服务发现的工作原理后,我们开始进入前期工作阶段。&lt;/p>
&lt;h2 id="31-性能压测">3.1 性能压测&lt;/h2>
&lt;p>从社区的资料来看,dubbo3各方面都非常不错,但是我们还得自己检验一次,所以我们使用当前在用的dubbo2内部定制版和dubbo3的性能压测,压测的主要场景在于同步调用,异步场景只做了dubbo3的压测, &lt;strong>以下压测数据和结论仅供参考&lt;/strong> 。结果表明dubbo3在性能上面确实做了很多的优化,在相同cpu使用率的情况下,dubbo3的tps是要高于dubbo2的;tps相当的情况下,dubbo3的cpu使用率要低于dubbo2。尤其是dubbo2的接口级与dubbo3的实例级,在tps相当的情况下,dubbo3的cpu使用率要较定制版的dubbo2低20%左右。&lt;/p>
&lt;p>压测环境:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>类别&lt;/th>
&lt;th>版本&lt;/th>
&lt;th>机器配置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Provider&lt;/td>
&lt;td>dubbo 3.0.4&lt;/td>
&lt;td>4C8G&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Consumer&lt;/td>
&lt;td>dubbo 3.0.4&lt;/td>
&lt;td>4C8G&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Provider&lt;/td>
&lt;td>dubbo 2.5.3.22(基于2.5.3版本定制)&lt;/td>
&lt;td>4C8G&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Consumer&lt;/td>
&lt;td>dubbo 2.5.3.222(基于2.5.3版本定制)&lt;/td>
&lt;td>4C8G&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>测试场景:&lt;/p>
&lt;p>使用的是Dubbo协议,接口没有其它逻辑,直接将输入返回给消费者, 接口数据包大小500B,每个场景压30分钟。&lt;/p>
&lt;p>测试数据 (仅供参考):&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-7.png" alt="pingan">&lt;/p>
&lt;h2 id="32-升级前调研">3.2 升级前调研&lt;/h2>
&lt;p>做了压测得到dubbo2和dubbo3的压测数据后,我们开始计划将 Dubbo3 引入公司进行试点,此时,我们需要考虑dubbo3与dubbo2的兼容和迁移重构问题,升级目标,以及dubbo3提供有哪些能力支持升级和迁移。&lt;/p>
&lt;h3 id="321-升级的兼容和迁移重构问题">3.2.1 升级的兼容和迁移重构问题&lt;/h3>
&lt;p>考虑到公司的系统规模,要将dubbo2升级到dubbo3却不是一个简单的过程,尤其是公司的dubbo2版本在原开源版本基础之上做了不少优化和扩展,涵盖了ops服务治理、monitor数据指标监控、服务注册和发现、RPC灰度路由、链路分析、序列化编解码、作为其他基础框架的底层支持等多个方面,同时dubbo3社区也处于活跃的状态,我们也希望能够持续享受dubbo社区的技术红利,在这样的背景下不得不考虑三个问题:&lt;/p>
&lt;ol>
&lt;li>需要解决公司版本的dubbo2与dubbo3的兼容问题;&lt;/li>
&lt;li>原有功能的迁移重构问题;&lt;/li>
&lt;li>不在dubbo3的源码上做改动,保持和社区版本一致。&lt;/li>
&lt;/ol>
&lt;p>得益于dubbo 良好的扩展能力,我们可以通过dubbo 的SPI和IoC模块在dubbo3的基础之上优雅的兼容公司版本的dubbo2,不用改动dubbo3源码,只要研发dubbo3扩展包跟随dubbo3版本的API升级即可,这个升级改动的成本和从社区获取红利相比是比较小的。&lt;/p>
&lt;h3 id="322-升级目标">3.2.2 升级目标&lt;/h3>
&lt;p>既然历史包袱的解决方案已经有了,那么就要思考升级的目标了。首先确定的是,最终我们将会采用实例级的服务注册和服务发现,其次我们目前使用的注册中心是zookeeper,而dubbo社区更推荐使用的注册中心是nacos,而且我们在验证阶段时也暴露过几个在zookeeper上出现而在nacos上没有出现的问题,这也使得我们开始考虑将来是否将注册中心最终也迁移到nacos上。&lt;/p>
&lt;p>同时,我们也希望整个迁移过程是平滑、可控的,我们整体方案也要将风险把控作为核心要点考虑,尽可能的做到失败降级、实时可控。&lt;/p>
&lt;p>综上,我们将升级的目标归纳为下面几点:&lt;/p>
&lt;p>1)平滑的从dubbo2升级到dubbo3。&lt;/p>
&lt;p>2)将接口级服务注册和发现模式平滑的迁移到应用级服务注册和发现模式。&lt;/p>
&lt;p>3)为后面平滑迁移注册中心做好准备。&lt;/p>
&lt;p>4)迁移过程可监控、可观测。&lt;/p>
&lt;p>5)迁移过程要可灰度、可实时管控。&lt;/p>
&lt;p>6)统一dubbo3的通用配置规范,尽量适配原dubbo2的export和refer方式。&lt;/p>
&lt;h3 id="323-dubbo3对于迁移的支撑能力">3.2.3 dubbo3对于迁移的支撑能力&lt;/h3>
&lt;p>前面介绍的是我们的目标,但是如何把dubbo3的原生设计理念融入到现实情况中呢?以下是我们的相关思考,并在验证过程中。&lt;/p>
&lt;p>首先dubbo3能够支持在registryUrl上通过参数管理provider和consumer以不同的模式进行服务注册和服务发现,其中核心参数名有: registry-type, registry-protocol-type, register-mode。&lt;/p>
&lt;p>其次,dubbo3可以支持使用多个注册中心,不同的注册中心通过上面的registryUrl参数控制注册中心的服务注册模式和服务发现模式。而且还可以通过ProviderConfig和ConsumerConfig这两个这两个Config类分别管理provider侧和consumer侧使用的注册中心。在consumer侧,如果有使用多个注册中心,默认会使用ZoneAwareCluster创建的ZoneAwareClusterInvoker来进行负载均衡,从类名上可以看出,该ClusterInvoker是有提供区域感知的能力,查看源码时发现它还提供了preferred的功能,只在相应的registryUrl中添加了preferred=true,这个registryUrl创建的ClusterInvoker就会被优先调用。&lt;/p>
&lt;p>在同一注册中心进行接口级迁移到实例级的场景中,dubbo3的MigrationInvoker也提供了相应的支持,MigrationInvoker可以根据MigrationRule来控制实例级的RPC流量,并且根据MigrationRuleListener能够实时监听到指定应用的MigrationRule的变更。&lt;/p>
&lt;p>关于RPC 的监控在dubbo中一直由MonitorFilter和DubboMonitor提供RPC监控数据的收集和上报,收集的数据有消费者的ip端口、提供者的ip端口、应用名称、DubboService、Method、以及成功数、失败数、输入字节数、输出字节数、耗时、并发数等,&lt;/p>
&lt;p>这些能力能够满足基本的迁移工作,结合我们的现状来看,相对升级目标要求的平滑迁移,迁移流量可观测、可灰度、可管控还有一些距离,不过在梳理dubbo3这块能力的时候,也找到了相对简单的扩展方案。到此,对于整体的迁移方案也有了一个大致的雏形。&lt;/p>
&lt;h1 id="4-升级迁移方案设计">4 升级&amp;amp;迁移方案设计&lt;/h1>
&lt;p>方案的设计重点放在&amp;quot;平滑、可控&amp;quot;两点,根据dubbo3的新架构,目前正在验证中的迁移方案示意图如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/pingan-8.png" alt="pingan">&lt;/p>
&lt;p>从上图可以看出,在整个升级迁移的过程中,应用域中会存在多个dubbo版本,dubbo3是能够兼容社区的dubbo2版本,而我们公司内部的dubbo2版本是基于dubbo2.5.3开源版本深度定制过的,在ops服务治理、monitor数据指标监控、服务注册和发现、RPC灰度路由、序列化编解码等方面都做了扩展定制,我们的思路是由dubbo3基于dubbo的SPI采用扩展的方式或者ExtensionLoader的Wrapper模式去兼容定制版的dubbo2。&lt;/p>
&lt;p>除了应用外,在dubbo3的架构基础上划分了3个逻辑域,分别是注册域、配置管控域和监控域。注册域主要服务于服务的注册和发现,例如provider在DubboService暴露时,将服务信息和元数据信息上报到注册域的注册中心和元数据中心,consumer通过注册中心和元数据中心来发现服务。配置管控域主要是管理应用配置和迁移流量管控,dubbo3提供的配置中心支持自身能力的配置,所以流量规则的配置由dubbo3的配置中心进行维护,dubbo3的DynamicConfigration提供了很多关于动态配置的方法可以直接使用。监控域除了原RPC流量的监控外,还细分了迁移流量的监控,在迁移过程中,可以通过监控直观的看到迁移流量的现状,出现问题时,也可以及时报警通知相关人员介入。&lt;/p>
&lt;p>整个升级过程分为3个阶段:&lt;/p>
&lt;p>第一阶段:将dubbo2升级到dubbo3的接口级,验证功能、兼容性、性能和稳定性&lt;/p>
&lt;p>第二阶段:接口级和应用级双注册,通过MigrationRule和RegistryMigrationRule管理RPC流量&lt;/p>
&lt;p>第三阶段:全面切换到应用级,撤掉MigrationRule和RegistryMigrationRule&lt;/p>
&lt;h2 id="41-dubbo3扩展兼容dubbo2定制版本">4.1 dubbo3扩展兼容dubbo2定制版本&lt;/h2>
&lt;p>考虑到dubbo3社区版本的迭代情况,最终决定dubbo3兼容dubbo2定制版本的插件以SDK的方式单独维护,实现兼容的扩展功能主要有如下内容:&lt;/p>
&lt;ol>
&lt;li>RPC 正向透递与反向透传&lt;/li>
&lt;/ol>
&lt;p>在consumer侧和provider侧扩展Filter接口实现类,为正向与反向透传数据实现其发送和接收的功能。Dubbo2定制版是在序列化编解码层面对RpcResult进行了修改,要兼容这一逻辑也只能在序列化编解码层面去支持,采用Wrapper模式对Codec2这个SPI进行增强,与其它扩展类一并实现该兼容功能。&lt;/p>
&lt;ol start="2">
&lt;li>RPC 灰度路由&lt;/li>
&lt;/ol>
&lt;p>扩展Dubbo 的Router、 Cluster和ConfiguratorFactory等SPI,与内部的eunomia灰度管控平台集成实现RPC灰度路由,替换并兼容掉原dubbo2定制版在其源码层面修改实现的灰度路由功能。&lt;/p>
&lt;ol start="3">
&lt;li>monitor数据指标监控&lt;/li>
&lt;/ol>
&lt;p>扩展Protocol、MonitorFilter、Monitor等SPI,与内部的监控中心完成对接,与dubbo2定制版的监控逻辑保持一致。&lt;/p>
&lt;ol start="4">
&lt;li>ops 支持实例级&lt;/li>
&lt;/ol>
&lt;p>在ops层面,除了要兼容原接口级的服务管控外,还要添加实例级的服务管控。&lt;/p>
&lt;ol start="5">
&lt;li>其它中间件兼容&lt;/li>
&lt;/ol>
&lt;p>除了dubbo本身的兼容外,内部还有部分自研的中间件也是有依赖dubbo或者跟dubbo有关联的,还要对这些中间件进行改造升级。&lt;/p>
&lt;h2 id="42-迁移扩展">4.2 迁移扩展&lt;/h2>
&lt;p>在dubbo3原有能力基础上,也要另外进行扩展以提供平滑迁移的能力,我们构想的设计方案如下:&lt;/p>
&lt;ol>
&lt;li>扩展支持注册中心的迁移可灰度、可管控&lt;/li>
&lt;/ol>
&lt;p>在dubbo3中,当consumer侧应用了多个注册中心时,默认会通过ZoneAwareCluster创建ZoneAwareClusterInvoker来进行负载均衡,参考其实现可以扩展一个Cluster实现类和一个ClusterInvoker实现类将ZoneAwareCluster替换掉,注册中心迁移的流量管理、灰度、降级等能力都在扩展的ClusterInvoker中去实现&lt;/p>
&lt;ol start="2">
&lt;li>扩展支持接口级到实例级迁移规则的全局配置管理&lt;/li>
&lt;/ol>
&lt;p>MigrationRule由MigrationRuleListener通过DynamicConfiguration监听指定的应用的迁移规则,如果一个系统拥有成百上千个微服务应用时,由这种方式去管理,维护成本将会变高,我们借鉴这个方法实现了全局级别的MigrationRule管理能力。&lt;/p>
&lt;ol start="3">
&lt;li>扩展迁移流量可观测、可报警&lt;/li>
&lt;/ol>
&lt;p>dubbo RPC的流量监控已经有MonitorFilter和DubboMonitor实现了,只是MonitorFilter不能识别本次RPC请求的Invoker对象是通过哪个注册中心进行服务发现的,以及该Invoke对象的服务发现模式是接口级还是实例级的;,我们在consumer侧新增一个ClusterFilter接口和Filter接口去实现这个识别逻辑。&lt;/p>
&lt;ol start="4">
&lt;li>迁移组件开关&lt;/li>
&lt;/ol>
&lt;p>在扩展的最后,要考虑迁移组件下线的问题,即使要下线也不可能再次调整业务工程将迁移组件全部从依赖中删除掉,所以需要通过开关控制迁移组件的功能下线。&lt;/p>
&lt;h2 id="43-配置统一管理">4.3 配置统一管理&lt;/h2>
&lt;p>在升级和迁移过程中,我们可能会随时调整注册中心和迁移规则的配置参数,为减少出错的风险以及业务工程升级改动的工作量,这些公共的配置需要统一管理维护起来,dubbo3的配置中心正常能够把这个任务较好的承接下来。&lt;/p>
&lt;p>最终我们又扩展了一个配置加载的组件,通过我们公司内部的配置中心管理维护迁移组件的开关和配置中心的连接地址与超时等配置参数。有了这个组件后,新的应用可以不用担心dubbo3和迁移的公共配置,老的应用也减少了这部分公共配置的调整工作量。&lt;/p>
&lt;h2 id="44-风险预案">4.4 风险预案&lt;/h2>
&lt;p>dubbo作为一个提供底层支撑能力的微服务框架,我们始终把稳定性的要求放在首位,升级过程中任何一点意外,都可能导致线上问题,所以我们整个方案都是在面向失败、面向风险设计的。除了在扩展的迁移组件中实现了主动降级外,也着重考虑了一些极端情况,同时为这些极端情况提供风险预案。线上环境可能会出现各种意想不到的情况,在迁移过程中需要预先思考各种风险,准备完善的应对处理预案,保证系统快速恢复。&lt;/p>
&lt;h2 id="45-小结">4.5 小结&lt;/h2>
&lt;p>dubbo2是一个优秀的微服务框架,提供的SPI以及Extension机制能够非常方便的让用户去扩展实现想要功能。dubbo3在其基础之上,丰富了不少新的SPI,我们花了很长的时间去设计迁移方案,真正花在迁移组件上的开发时间较短。&lt;/p>
&lt;p>dubbo3整体架构升级调整对于过去的服务注册压力也得到了解决。性能上也做了优化,架构升级后的dubbo3也更适应目前云原生的架构,dubbo 3.1.x 版本支持sidecar和proxyless的mesh方案,而且社区也在准备开源java agent 方式的proxyless,这样就能较好的将微服务架框的framework与数据面解耦,降低微服务框架的维护成本和升级成本。&lt;/p>
&lt;h1 id="5-社区协作">5 社区协作&lt;/h1>
&lt;p>目前该项目仍然在持续升级中,我们跟社区保持着紧密的联系,期间碰到不少问题,都得到了社区开发同学耐⼼解答并最终给予解决。对于要升级 Dubbo3 的⽤户,可以在社区的Github User Issue(https://github.com/apache/dubbo/issues/9436) 进⾏登记,想参与社区的同学们也可以关注 Dubbo 官⽅公众号(搜索 Apache Dubbo)了解更多关于dubbo社区的进展。&lt;/p></description></item><item><title>Blog: 全国首个政企采购云平台:政采云的混合云跨网方案实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/03/22/%E5%85%A8%E5%9B%BD%E9%A6%96%E4%B8%AA%E6%94%BF%E4%BC%81%E9%87%87%E8%B4%AD%E4%BA%91%E5%B9%B3%E5%8F%B0%E6%94%BF%E9%87%87%E4%BA%91%E7%9A%84%E6%B7%B7%E5%90%88%E4%BA%91%E8%B7%A8%E7%BD%91%E6%96%B9%E6%A1%88%E5%AE%9E%E8%B7%B5/</link><pubDate>Wed, 22 Mar 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/03/22/%E5%85%A8%E5%9B%BD%E9%A6%96%E4%B8%AA%E6%94%BF%E4%BC%81%E9%87%87%E8%B4%AD%E4%BA%91%E5%B9%B3%E5%8F%B0%E6%94%BF%E9%87%87%E4%BA%91%E7%9A%84%E6%B7%B7%E5%90%88%E4%BA%91%E8%B7%A8%E7%BD%91%E6%96%B9%E6%A1%88%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>对云岛业务结构的公司来说,云平台属于公司内部、完全可控的局域网,而岛端则是有自己安全网络策略的独立内部网络。需要云岛通信时,会基于需求,按客户要求走流程开通一些端口,这个过程需要一定的成本且不完全可控。业务上,如果这种跨网需求增多,则会逐渐变成痛点。如果可以搭建一个透明的跨网传输网络,配合良好的顶层设计,就可以在业务支撑、安全管控和运维成本中寻求较好的平衡。&lt;/p>
&lt;p>本文将介绍政采云基于 Dubbo 的跨网方案落地过程中面临的技术挑战、社区合作以及更深层次抽象的一些思考。在政采云这种政企业务场景中的数据跨网,与业界公有云、自建私有云的公司相比,既有共性又有自己的特点,希望能为大家提供新的思路或者启发。&lt;/p>
&lt;h2 id="前言">前言&lt;/h2>
&lt;p>稳定、高效、可靠的基础设施是互联网企业应对业务高峰流量的底层基石。作为政采云的基础技术平台,基础平台部一直致力于通过业内前沿技术的落地,保障公司内部所有业务在线生产系统所依赖的基础技术平台能稳定、安全、低成本、可持续地运行与发展。&lt;/p>
&lt;p>由于公司对 Dubbo 框架的重度使用,&lt;strong>跨网数据传输系统&lt;/strong>一般基于 Dubbo 特性开发,在政采云内部就有多个版本的实现。&lt;/p>
&lt;p>早在几年前,政采云就上线了基于 Dubbo Filter 转发的方案,它解决了岛到云的单向数据传输,安全认证等问题。另外,业务部门也有按照自己的需求,推出网状点对点的方案,实现了一定程度的透明传输。&lt;/p>
&lt;p>结合前两年的探索实践以及业界相关领域技术的成熟度,2022年下半年,我们对各跨岛方案,进行了整合升级,也就是现在的&lt;strong>高速公路&lt;/strong>方案,保障跨岛标准化同时,解决了之前方案实践过程中面临的很多业务痛点,包括:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>单向传输&lt;/strong>:因为架构原因,如需双向需要对等重新部署一套,成本较大。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>白名单开通成本高&lt;/strong>:点对点的网状架构,需要两两开通白名单,因为政企网络特殊性,开通流程复杂且慢。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>平台维护成本高&lt;/strong>:业务各自一套数据传输平台,重复建设且运维成本高。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>公共功能的缺失&lt;/strong>:核心功能,业务可以按需开发,但是数据审计、链路追踪、可观测性等公共特性,往往没有足够投入。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="1-跨网数据传输系统演进">1. 跨网数据传输系统演进&lt;/h2>
&lt;h3 id="11-历史架构">1.1 历史架构&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-1.png" alt="img">&lt;/p>
&lt;p>​&lt;/p>
&lt;p>自左向右、自下而上进行模块介绍:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>业务Web&lt;/strong>:业务 Web 作为数据发送方,调本地 集群 Provider 时,携带跨岛信息过去(Dubbo 上下文)。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>岛业务Center&lt;/strong>:本地虚拟Provider,通过Filter拦截跨岛请求,通过http传送到云平台 Dubbo 网关,返回数据后反序列化返回岛业务 web。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Dubbo网关&lt;/strong>:接收 Http 请求,通过泛化调用云端 Provider,处理数据后返回业务 Center。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>云业务Center&lt;/strong>:普通 Dubbo Provider。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="12-高速公路架构">1.2 高速公路架构&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-2.png" alt="img">&lt;/p>
&lt;p>​&lt;/p>
&lt;p>&lt;strong>1.2.1 隧道机制&lt;/strong>&lt;/p>
&lt;p>隧道技术是一种通过使用&lt;strong>互联网络&lt;/strong>的&lt;strong>基础设施&lt;/strong>在网络之间传递数据的方式。使用隧道传递的&lt;strong>数据&lt;/strong>(或负载)可以是不同协议的数据帧或包。&lt;/p>
&lt;p>高速公路架构中,使用了隧道这个概念。两端(业务层)是 Dubbo 私有协议,跨网传输过程中,则使用了 http 协议,http 协议可以更好的被中间设备、网关识别转发。这个机制的最大便利在于对业务的低侵入性。对于业务集群的应用完全不需要修改。
&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-3.png" alt="img">&lt;/p>
&lt;p>除了路由标记,出口/入口 Dubbo 协议字节流没有任何业务外信息,所以可以路由任何 Dubbo 请求。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-4.png" alt="img">&lt;/p>
&lt;p>&lt;strong>1.2.2 主要节点&lt;/strong>&lt;/p>
&lt;p>&lt;strong>客户端 Sdk&lt;/strong>:不改变用户使用 Dubbo 的方式,多种形式提供Dubbo的路由。&lt;/p>
&lt;p>**Dubbo 出口网关:**代理 Dubbo 流量出口。&lt;/p>
&lt;p>**Dubbo 入口网关:**代理 Dubbo 流量入口。&lt;/p>
&lt;p>**统一网关:**基于 Apisix,代理跨网间所有流量,可以扩展鉴权、审计、限流等特性&lt;/p>
&lt;h2 id="2-挑战与应对之策">2. 挑战与应对之策&lt;/h2>
&lt;p>如前言中所述,已有的几个方案设计上存在了一些问题,落地后也限制了使用了场景。在架构上,我们提出了高速公路方案,选择了全双工的对等网络传输框架。角色上,云平台定位一个特殊的岛端应用,遵循P2P实施原则。而对用户而言,高速公路是一个通往岛端的隧道,遵循对用户透明原则。我们可以先来看下在搭建平台的过程中面临的一些挑战以及解法。&lt;/p>
&lt;h3 id="21-技术挑战">2.1 技术挑战&lt;/h3>
&lt;p>结合当下跨网数据传输系统面临的处境,并对业界 Dubbo 跨网方案做过一番调研后,在平台搭建上确定了如下三期目标:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>一期目标&lt;/strong>:网络能力建设,简单来说是搭建基于 Dubbo 的传输通道,上层功能先维持不变。&lt;/li>
&lt;li>&lt;strong>二期目标&lt;/strong>:业务上,找业务先行试点,基于反馈,小步快跑,快速迭代;技术上,寻求 Dubbo 社区协作,增强对Dubbo相关技术风险的把控,同时抽离通用特性,反馈社区。&lt;/li>
&lt;li>&lt;strong>三期目标&lt;/strong>:抽象出更通用的网络框架,从而使语言层,传输协议层、及中间件层独立扩展,一键切换。&lt;/li>
&lt;/ul>
&lt;p>在上述三期目标基本落地后,高速公路系统不仅可以跑起来,同时拥有非常强大的扩展性,更好的承接业务需求及共建。在这过程中,我们需要解决不少技术问题。&lt;/p>
&lt;p>&lt;strong>2.1.1 客户端路由&lt;/strong>&lt;/p>
&lt;p>如前面历史方案所述,其场景被限制为岛到云的单向数据传输,特点如下:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>客户端无路由能力&lt;/strong>:Consumer 端只能指定是否路由到云平台,而不能指定其他岛端。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>基于filter的扩展&lt;/strong>:Dubbo的 Filter 并不是为路由设计的,在此基础上较难扩展。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>需要本地Provider角色&lt;/strong>:Consumer 端发出的请求,必须由一个注册在 Zookeeper 下的 Provider 兜住,然后 Filter 根据上下文决定是否转发,这就限制了业务方必须部署一个本地 Provider 应用(哪怕是空应用),才能做到跨网访问。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>我们要解决的问题之一,就是打破单向传输瓶颈,客户端可以更自由的路由到目标云/岛。我们设计了以下几种路由方式:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>注解方式&lt;/strong>:使用@DubboReference提供的通用 parameters 参数,设置路由目标,可以达到方法粒度的路由。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@DubboReference&lt;/span>&lt;span style="color:#719e07">(&lt;/span>check &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">false&lt;/span>&lt;span style="color:#719e07">,&lt;/span> parameters &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">{&lt;/span>&lt;span style="color:#2aa198">&amp;#34;ENV_SHANGHAI&amp;#34;&lt;/span>&lt;span style="color:#719e07">,&lt;/span> &lt;span style="color:#2aa198">&amp;#34;ALL&amp;#34;&lt;/span>&lt;span style="color:#719e07">})&lt;/span> &lt;span style="color:#586e75">//all表示所有方法,可以单独指定
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>&lt;span style="color:#268bd2">private&lt;/span> DemoService demoService&lt;span style="color:#719e07">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>配置中心指定&lt;/strong>:把以上parameters = {&amp;ldquo;ENV_SHANGHAI&amp;rdquo;, &amp;ldquo;ALL&amp;rdquo;} 信息,在配置中心配置,达到同样的效果,这种方式对代码完全无侵入。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>线程指定&lt;/strong>:这种方式最灵活。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>AddressZoneSpecify&lt;span style="color:#719e07">.&lt;/span>setAddress&lt;span style="color:#719e07">(&lt;/span>Enviroment&lt;span style="color:#719e07">.&lt;/span>SHANGHAI&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>demoService&lt;span style="color:#719e07">.&lt;/span>play&lt;span style="color:#719e07">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;p>无论哪种路由方式,基于“用户透明“的原则,都不改变用户使用 dubbo 的方式。&lt;/p>
&lt;p>&lt;strong>2.1.2 Dubbo请求地址切换&lt;/strong>&lt;/p>
&lt;p>客户端路由最小限度地侵入业务代码,达到了透明调用远程服务的目标。但是,用户仍旧需要部署一套虚拟 Provider 应用,接收请求后按规则进行路由。&lt;/p>
&lt;p>为了避免部署多余的应用,我们需要有一定的机制,直接把dubbo流量切换到远程。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-5.png" alt="img">&lt;/p>
&lt;p>​&lt;/p>
&lt;p>解决了切换问题后,本地的 APP2 不再需要,甚至zk也可以移除。当然,如果业务同时有本地和远程的调用需要,也可以继续存在。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-6.png" alt="img">&lt;/p>
&lt;p>​&lt;/p>
&lt;p>原先,我们准备通过Dubbo的Route自定义扩展,去实现动态切换地址的能力。查阅资料后,发现Dubbo已经提供了类似能力。&lt;/p>
&lt;p>&lt;a href="https://cn.dubbo.apache.org/zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/">https://cn.dubbo.apache.org/zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/&lt;/a>&lt;/p>
&lt;p>该特性放在Dubbo的子工程dubbo-spi-extensions中,同样以Route扩展形式实现。&lt;/p>
&lt;p>但在实际使用过程中,我们遇到如下问题:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>不支持 Dubbo2&lt;/strong>:使用 Dubbo2 时,直接以异常的形式提醒暂不支持。&lt;/li>
&lt;li>&lt;strong>NPE异常:&lt;/strong> 某些场景下调用出现了NPE异常。&lt;/li>
&lt;li>&lt;strong>丢失部分信息:&lt;/strong> Router下构建新 Invocation 时,丢失了 version、group等信息。&lt;/li>
&lt;li>&lt;strong>重试异常:&lt;/strong> 远程 Provider 如果发生了异常,客户端在重试的时候,选择了本地集群 Provider 调用,造成错误.&lt;/li>
&lt;/ul>
&lt;p>作为一个尝鲜新特性,我们理解功能存在不稳定的情况。但这个功能作为我们跨网方案的技术要点,又必须解决。所以,我们通过PR的形式,把相应补丁提交到Dubbo社区。这个过程中,我们联系到了Dubbo PMC 远云大佬,一起讨论和完善PR,直到解决所有已知问题。&lt;/p>
&lt;p>&lt;strong>2.1.3 出口网关的实现&lt;/strong>&lt;/p>
&lt;p>在上图中,通过切换地址,我们似乎可以直接访问远程应用,并且架构非常简单。但是遗憾的是,存在几个难以解决的问题:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>网关组件的限制&lt;/strong>:在云岛/岛岛间,存在一系列网关组件,来提供转发、负载均衡的功能,比如SLB、NGINX、WAF。这些组件并不能识别私有的 Dubbo 流量并转发&lt;/li>
&lt;li>&lt;strong>ip白名单开通成本高:&lt;/strong> 类似 P2P 方案,需要点对点开通 IP 白名单,成本巨大。&lt;/li>
&lt;li>&lt;strong>升级维护复杂:&lt;/strong> 客户端通过集成 SDK 的形式转发,后续如需要劫持流量进行扩展,需要同时对每个接入应用进行升级。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-7.png" alt="img">&lt;/p>
&lt;p>​&lt;/p>
&lt;p>针对以上问题,我们的设计中,需要加入 Dubbo 网关的角色,来实现以下目标。&lt;/p>
&lt;p>① &lt;strong>两端ip收敛&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>显著减少网关长连接数量&lt;/li>
&lt;li>弱化服务注册发现流程(每个环境只有一个 Dubbo 网关,直接配置即可互相发现)&lt;/li>
&lt;li>简化鉴权、认证流程。一条链路可以使用白名单,一群则只能配置较复杂的鉴权&lt;/li>
&lt;/ul>
&lt;p>② &lt;strong>两端功能收敛&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>客户端的 SDK 专注路由功能,基本不用升级&lt;/li>
&lt;li>扩展功能放在 Dubbo-Proxy,统一升级,业务端无感知&lt;/li>
&lt;/ul>
&lt;p>Dubbo-Proxy 作为业务网关,可以减轻对业务端的侵入,起到类似分布式运行时(Dapr)作用。但是,在引入之前,需要解决一些现实的技术问题。其中,最重要的问题是如何接收陌生的 Dubbo 流量,然后进行转发。做了一些相关调研后,有两个方案可用:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>通用Provider&lt;/strong>:直接在 Dubbo-Proxy 注册一个普通的通用 Service,客户端的 SDK 利用 Filter,劫持流量,直接调用通用 Service 后处理数据返回。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>**注册虚拟节点:**该方案来源于远云。客户端在本地zk订阅远程节点时,通知 Proxy,Proxy 获取订阅的信息后(预先订阅所有 zk 变更),主动注册相应虚拟 Service(对 zk 来说,注册一个节点的参数只是字符串)到zk上。这样,可以把客户端的远程流量“骗”到 Proxy ,Proxy 再使用服务端泛化,接收请求并转发。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>以上两种方案,都可以实现出口网关。但是,在设计上,角色间需要多次交互,才能达到目的。那么,是否有更简洁的方式,直接支持这种接收和转发呢?&lt;/p>
&lt;p>首先,我们对 Dubbo 源码进行了调研,看 Provider 接收到陌生流量(无相应Service)后会如何处理,是否有扩展点可以拦截。发现在 Byte 流解析阶段,Dubbo 即对 Service 进行了检查,不存在直接抛异常返回。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-8.png" alt="img">
​&lt;/p>
&lt;p>在 Provider 处理的生命周期中,Decode 出于非常早期的阶段,几乎没有什么扩展点可以拦截处理。因为快速失败的理念,早期的检测确实可以避免后面无谓的代码执行消耗。但是,对比 Spring ,Dubbo 在扩展性上是有不足的,即对于一个通用的异常,却没有相应的扩展机制。&lt;/p>
&lt;p>我们决定在 decode 的基础上,加上对这个异常的扩展。主要思路是,在 decode 被调用处,catch 住这块异常,通过 SPI 的形式,获取扩展实现,可以定制异常信息,也可以控制 decode 流程重试。这块修改难度并不大,私有版本上顺利通过测试,同时提交 PR 到社区。这个过程中,远云大佬帮忙发现了一个并发安全的 bug,并给了不少减少风险的建议。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//解码结束后,无论是否异常,都将进入这个方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">handleRequest&lt;/span>&lt;span style="color:#719e07">(&lt;/span>&lt;span style="color:#268bd2">final&lt;/span> ExchangeChannel channel&lt;span style="color:#719e07">,&lt;/span> Request req&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#268bd2">throws&lt;/span> RemotingException &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>req&lt;span style="color:#719e07">.&lt;/span>error &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Give ExceptionProcessors a chance to retry request handle or custom exception information.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> String exPs &lt;span style="color:#719e07">=&lt;/span> System&lt;span style="color:#719e07">.&lt;/span>getProperty&lt;span style="color:#719e07">(&lt;/span>EXCEPTION_PROCESSOR_KEY&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>StringUtils&lt;span style="color:#719e07">.&lt;/span>isNotBlank&lt;span style="color:#719e07">(&lt;/span>exPs&lt;span style="color:#719e07">))&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>ExceptionProcessor&lt;span style="color:#719e07">&amp;gt;&lt;/span> extensionLoader &lt;span style="color:#719e07">=&lt;/span> channel&lt;span style="color:#719e07">.&lt;/span>getUrl&lt;span style="color:#719e07">().&lt;/span>getOrDefaultFrameworkModel&lt;span style="color:#719e07">().&lt;/span>getExtensionLoader&lt;span style="color:#719e07">(&lt;/span>ExceptionProcessor&lt;span style="color:#719e07">.&lt;/span>class&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExceptionProcessor expProcessor &lt;span style="color:#719e07">=&lt;/span> extensionLoader&lt;span style="color:#719e07">.&lt;/span>getOrDefaultExtension&lt;span style="color:#719e07">(&lt;/span>exPs&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">boolean&lt;/span> handleError &lt;span style="color:#719e07">=&lt;/span> expProcessor&lt;span style="color:#719e07">.&lt;/span>shouldHandleError&lt;span style="color:#719e07">(&lt;/span>error&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>handleError&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//获取异常扩展,执行wrapAndHandleException操作,需要重试的场景可以抛出retry异常
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> msg &lt;span style="color:#719e07">=&lt;/span> Optional&lt;span style="color:#719e07">.&lt;/span>ofNullable&lt;span style="color:#719e07">(&lt;/span>expProcessor&lt;span style="color:#719e07">.&lt;/span>wrapAndHandleException&lt;span style="color:#719e07">(&lt;/span>channel&lt;span style="color:#719e07">,&lt;/span> req&lt;span style="color:#719e07">)).&lt;/span>orElse&lt;span style="color:#719e07">(&lt;/span>msg&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res&lt;span style="color:#719e07">.&lt;/span>setErrorMessage&lt;span style="color:#719e07">(&lt;/span>&lt;span style="color:#2aa198">&amp;#34;Fail to decode request due to: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> msg&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res&lt;span style="color:#719e07">.&lt;/span>setStatus&lt;span style="color:#719e07">(&lt;/span>Response&lt;span style="color:#719e07">.&lt;/span>BAD_REQUEST&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> channel&lt;span style="color:#719e07">.&lt;/span>send&lt;span style="color:#719e07">(&lt;/span>res&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//handleRequest过程中的retry控制
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">received&lt;/span>&lt;span style="color:#719e07">(&lt;/span>Channel channel&lt;span style="color:#719e07">,&lt;/span> Object message&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#268bd2">throws&lt;/span> RemotingException &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//解码
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> decode&lt;span style="color:#719e07">(&lt;/span>message&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> handler&lt;span style="color:#719e07">.&lt;/span>handleRequest&lt;span style="color:#719e07">(&lt;/span>channel&lt;span style="color:#719e07">,&lt;/span> message&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">catch&lt;/span> &lt;span style="color:#719e07">(&lt;/span>RetryHandleException e&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">(&lt;/span>message &lt;span style="color:#719e07">instanceof&lt;/span> Request&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ErrorData errorData &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">(&lt;/span>ErrorData&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#719e07">((&lt;/span>Request&lt;span style="color:#719e07">)&lt;/span> message&lt;span style="color:#719e07">).&lt;/span>getData&lt;span style="color:#719e07">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//有定制,进行重试
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> retry&lt;span style="color:#719e07">(&lt;/span>errorData&lt;span style="color:#719e07">.&lt;/span>getData&lt;span style="color:#719e07">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span> &lt;span style="color:#719e07">else&lt;/span> &lt;span style="color:#719e07">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Retry only once, and only Request will throw an RetryHandleException
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> RemotingException&lt;span style="color:#719e07">(&lt;/span>channel&lt;span style="color:#719e07">,&lt;/span> &lt;span style="color:#2aa198">&amp;#34;Unknown error encountered when retry handle: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> e&lt;span style="color:#719e07">.&lt;/span>getMessage&lt;span style="color:#719e07">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> handler&lt;span style="color:#719e07">.&lt;/span>received&lt;span style="color:#719e07">(&lt;/span>channel&lt;span style="color:#719e07">,&lt;/span> message&lt;span style="color:#719e07">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关于ExceptionProcessor扩展,我们在官方扩展包Dubbo-Spi-Extensions中,提供了一个默认实现,允许控制重试解码,并自定义异常处理。&lt;/p>
&lt;p>&lt;strong>2.1.4 中心网关&lt;/strong>&lt;/p>
&lt;p>最新架构,已经非常接近最终实现了,但是缺了一个中心网关角色。引入这个网关(基于 Apisix )的原因:&lt;/p>
&lt;ul>
&lt;li>白名单问题:虽然 Dubbo 网关收敛了终端 IP,但是要实现岛岛互通,还是得两两互开白名单。引入中心网关(云平台)后,每个岛单独和云平台互开即可。白名单开通复杂度从O(n*n) 变为O(n)。&lt;/li>
&lt;li>统一网关的好处:作为公司级网关,可以统一对所有应用进行限流、鉴权、审计、可观测性等功能拓展。&lt;/li>
&lt;/ul>
&lt;h2 id="3-更多思考">3. 更多思考&lt;/h2>
&lt;p>无论公司内外,能选择的跨网方案非常多,我们会去选择一个能解决痛点的,而不是完美的方案。落地方案一般比较保守,但是对于架构的思考,一定是需要更超前的。&lt;/p>
&lt;p>&lt;strong>http协议导致的性能损失&lt;/strong>&lt;/p>
&lt;p>前面说到,在 Dubbo 网关和中心网关间,我们使用了 Http 协议。对比 Dubbo 等精简协议,Http 协议显然更臃肿。但是,也许这是现阶段最合适的方案。除了避免私有协议在网络设备中的“艰难前行”,Http 协议开发成本更低,相应落地风险也更小。一些新技术,也许是我们后续发展的方向。比如 Higress,支持 Triple 协议(基于 Http2)交换信息,在获得更高性能的同时,也解决了设备识别问题。但是选择 Higress,需要面对学习认知成本、新开源 BUG 多等问题,同时它可能更适合内部网络(即使跨公网也能搭建 VPN),而不是我们各私有岛端(客户自定义安全策略)的网络互通。&lt;/p>
&lt;p>&lt;strong>扩展性不足&lt;/strong>&lt;/p>
&lt;p>高速公路是一个基于 Dubbo 的跨网方案,在协议与框架层,与 Dubbo 的绑定比较深,但是它应该能做的更多。也许很快,会接入 Http、Mq 等应用协议的流量,或者 Python、Go 等语言的客户端,甚至是 Mysql 的数据互通。这个时候,要么对架构大改,要么各种兼容,这都不是我们想看到的。参考网络分层协议,我们也粗略地做了一个分层抽象规划。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/v3/users/zcy-9.png" alt="img">
​&lt;/p>
&lt;ul>
&lt;li>物理层打通:主要解决网络异构问题,即约定不同安全策略的子域如何通信。&lt;/li>
&lt;li>通讯协议层加速:前面讲到的应用层协议,需要做到允许独立扩展及切换。&lt;/li>
&lt;li>语言层编译加速:业务网关可能更适合使用 Golang,然后 Java 节点是否可以用 Native 优化性能?&lt;/li>
&lt;li>框架层功能升级:比如当前对 Dubbo 的定制开发,使用的 Apisix 中心网关是否可以扩展 dubbo 转 dubbo?&lt;/li>
&lt;li>任务编排:业务的跨网调度,不一定是A-&amp;gt;B-&amp;gt;C-&amp;gt;D,会不会是A、B同时完成后才能-&amp;gt;C-&amp;gt;D?&lt;/li>
&lt;li>更上层的控制面/治理面/运维面&lt;/li>
&lt;/ul>
&lt;h2 id="4-未来规划">4. 未来规划&lt;/h2>
&lt;p>随着高速公路方案在政采云的逐渐落地,我们未来会从稳定性、功能增强、新技术探索三个方面去做深、做广:&lt;/p>
&lt;p>(1)&lt;strong>稳定性&lt;/strong>:基础服务的稳定性是一切的基石,而这往往是不少研发同学容易忽视的一点,研发同学需“在晴天时修屋顶”。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>系统自身的健壮性&lt;/strong>:资源池化隔离、QoS 保障能力建设。&lt;/li>
&lt;li>&lt;strong>节点实例的稳定性&lt;/strong>:加固发现能力,持续完善异常检测工具(除了常规的健康检测,会从观测指标的不同纬度综合决策),自动进行异常实例的替换;加强数据运营,提升反馈能力。&lt;/li>
&lt;/ul>
&lt;p>(2)&lt;strong>功能增强&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>协议增强&lt;/strong>:当前只能对 Dubbo 流量转发,计划增加对 Http/Grpc等协议等支持,从而支持更多的场景(已有业务提此类需求)。&lt;/li>
&lt;li>&lt;strong>安全性增强&lt;/strong>:在中心网关 Apisix 开发鉴权、审计等插件,更好的控制跨网的调用与被调。&lt;/li>
&lt;li>&lt;strong>易用性增强&lt;/strong>:开发自动工单系统,对需要配置的事项,由业务测提工单,相应人员审核后自动配置,解放劳动力同时减少出错概率。&lt;/li>
&lt;/ul>
&lt;p>(3)&lt;strong>新技术探索&lt;/strong>&lt;/p>
&lt;p>​ 网关场景,通常有个两个比较明显的特点:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>并发量高: 多个应用复用同一个网关&lt;/p>
&lt;/li>
&lt;li>
&lt;p>行为轻量: 一般只有转发、权限校验等轻量操作&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>基于这两个特点,语言层性能开销在总性能开销中的占比,往往会业务应用更大,这个时候, Golang 等语言会比 Java更有优势。当前也在对 Dubbo-Go 调研,未来替换基于 Java 版 Dubbo 的网关应用。&lt;/p>
&lt;p>另外,Higress 方案看起来不错,必定会有许多值得我们学习的东西。&lt;/p></description></item></channel></rss>