首页 > 基础资料 博客日记

vivo 微服务架构实践之 Dubbo 性能优化

2026-01-15 11:00:02基础资料围观4

这篇文章介绍了vivo 微服务架构实践之 Dubbo 性能优化,分享给大家做个参考,收藏Java资料网收获更多编程知识

作者:互联网中间件团队-Zhang Zhenwei

本文为2025年 vivo 开发者大会互联网技术专场分享内容之一,在微信公众号《vivo互联网技术》对话框回复【2025VDC】获取 2025VDC 互联网技术会场议题相关资料。

 

在Java技术栈场景,vivo主要基于 Apache Dubbo 框架来作为微服务之间的通信桥梁,在内部业务的大规模实践过程中,我们碰到了质量、性能和容量等方面的挑战,通过一系列的扩展与优化,较好的解决了相关问题,助力业务更好保障质量,节省算力成本,提升研发效率。

 

1分钟看图掌握核心观点👇

图片

 

图片

图1 VS 图2,您更倾向于哪张图来辅助理解全文呢?欢迎在评论区留言。

 

一、Dubbo 在 vivo 的演进历程

1.1 vivo 微服务现状

图片

vivo自2015年通过微服务架构升级以赋能业务增长,通过全网治理,于2018年完成了全网Java技术栈RPC框架统一为Dubbo。 目前,该架构高效支撑了5亿用户、覆盖60+地区的业务体量,实现了万级微服务在十万级机器上的稳定运行,日均RPC调用量高达8000亿次。

 

1.2 Dubbo在vivo的演进历史

图片

Dubbo 是一款 RPC 服务开发框架,主要用于解决微服务架构中的通信与服务治理问题。它提供了服务定义,服务发现、负载均衡、流量管控等丰富能力。vivo在2015年,引入开源社区Dubbo作为Java技术栈RPC框架。而随业务规模发展,业务侧浮现框架版本碎片化现象,产生治理困难,维护成本高等问题。 在19年,vivo引入开源社区2.7.* 版本发布作为第一个基线版本,对业务侧进行了版本收敛。随后发布两个大基线版本,分别为建设三中心分离能力,和应用级注册发现能力。

 

1.3 Dubbo执行核心链路(概要)

图片

我们先简要介绍一下Dubbo的整体流程。 流程可分为上下两部分。上半部分呈现了由提供方、消费方、注册中心和元数据中心,协同完成的服务注册与引入。 下半部分为调用流程。Dubbo采用微内核与插件化设计,内部多个抽象层次。

 

 总体而言,一次RPC流程可分为两类: 

  • 一是启动即就绪的静态过程(如代理生成、服务列表缓存) 

  • 二是每次调用均需动态计算的部分(如路由、负载均衡、序列化,编解码),这些常是性能热点。

 

二、Dubbo 路由扩展及优化

2.1 Dubbo路由简介

图片

Dubbo路由是一套基于规则的精细化流量治理组件,其工作流程由服务治理侧向Dubbo下发路由策略,从而确保RPC请求能够被精准的路由至预期的服务实例列表。该机制是支撑灰度发布、机房容灾、环境隔离等流量治理能力的技术基石。 开源版本的Dubbo提供了应用级标签路由、条件路由和脚本路由等核心路由能力。我们在其基础上,扩展实现了接口级标签路由与就近路由两种增强机制。

 

2.2 就近路由

2.2.1 就近路由背景说明

图片

一般情况下,同机房内部的网络调用平均时延在0.1ms左右,而同城多机房间的平均时延在1ms-5ms,跨地域机房之间的网络时延则更大。 假设内部服务存在大量跨机房调用,尤其针对rt敏感业务,可能因为请求延时的增加,影响服务质量用户体验。 因此Dubbo就近路由应运而生,其可实现RPC过程优先使用同机房进行调用。 可以看到上图,提供方在注册会上报机房信息,消费方调用经过就近路由,只匹配同机房的提供方节点列表。

 

2.2.2 就近路由场景分析

图片

我们的理想方案如上方所示,是多机房共享注册中心,流量在就近路由的干涉下,在同机房内流转。 但此方案面临下方两个问题: 存在部分业务单机房部署现象,若强制进行同机房调用,会造成消费方无可用提供者。 同时存在多机房非均匀部署现象,若机房间部署规模差异较大,同机房调用可能造成小规模部署机房的业务集群雪崩。

 

2.2.3 就近路由实践

图片

为解决刚才的问题,我们最终实现如下:

  • 中间件联合CI/CD侧,在提供方服务部署时上报机房信息。

  • 消费方调用经过就近路由时会遍历提供方列表,优先筛选同机房提供方实例。

  • 新增阈值判断,当同机房提供方机器规模低于阈值时,路由会自动降级进行全量访问。这样可以有效避免单机房部署的无提供者问题 ,以及降低非均匀部署时的集群雪崩风险。

 

用上边的三个请求举例,在就近路由阶段: 

  • 请求1 发现同机房提供者部署规模超过阈值,属于安全调用,直接过滤出01机房节点。 

  • 请求2 发现同机房无可用提供者,则直接触发降级规则,返回全量节点。

  • 请求3 在就近路由阶段,发现同机房虽有可用提供者部署,但规模低于阈值,也直接触发降级规则,返回全量节点。

 

综上,就近路由通过简单的元数据标记和灵活的阈值规则,实现了流量的自动优化与隔离。其改造过程对业务代码无侵入,并带来延迟降低、网络带宽成本下降、稳定性提升的巨大收益。

 

2.3 标签路由能力说明

图片

接下来是标签路由,标签路由是一种在微服务架构中用于实现流量精细控制的服务治理策略。

 

其核心思想是通过控制面为服务实例打上自定义标签,标签路由根据消费方调用时指定的标签,将请求流量路由到匹配这些标签的提供方实例。 在Dubbo语义中,Dubbo标签分为动态标签与静态标签:如图所示,我们用通过配置中心下发动态标签,标记gray1包含a节点,标记gray2包含c节点,用于标识两个灰度环境。 而提供方部署时可以自带静态标签,静态标签随Dubbo注册发现流程被消费方在内存缓存。

 

以三个请求举例: 

  • 请求1 指定了gray1,标签路由会遍历提供方列表与gray1对应的列表进行交集计算,最后过滤a节点。 

  • 请求2 指定gray3,标签路由发现无可用节点,则请求会降级到无标签的机器,最后过滤b,d,e节点。 

  • 请求3 未指定标签,说明是基线环境调用,标签路由会筛选未打标签的机器,最后过滤b,d,e节点。

 

2.4 我们发现的性能问题

图片

在vivo大规模 Dubbo 提供方集群场景下,高峰期该业务消费方侧应用的整体 CPU 利用率约为60%,而其中负载均衡模块及路由模块的 CPU 占用率竟超过了30%! 通过火焰图分析可以观察到这些问题存在共性 : 相关方法均涉及遍历操作,其时间复杂度与提供方节点数量成正相关。在大规模集群部署环境下,路由与负载均衡模块因遍历计算产生了明显的资源消耗 。

 

2.4.1 路由优化实践--减少遍历运算

图片

优化思路

  • 降低消费方侧遍历次数:我们发现部分业务是完全不使用应用级标签路由的,而为了支持静态标签场景,应用级路由对于不带标签的请求,还是需要全量遍历,以筛选无静态标签的节点。这部分无效遍历会造成算力空转浪费。因此我们第一个优化是对此类业务关闭了应用级路由。

 

  • 根据火焰图我们了解到,在负载均衡中,负载均衡器需要全量遍历节点以获取权重。那么这时我们可以试图降低参与负载均衡计算的节点数:在负载均衡前,我们新增了虚拟分组。当路由筛选后的实例规模超过阈值后,虚拟分组模块会将实例列表拆分成多个小规模分组,通过对分组随机选择,倍数级降低了进入负载均衡的节点数,降低了负载均衡遍历次数。

 

2.4.2 路由优化实践

1.引入位图缓存

图片

由火焰图现象发现,无论是就近路由,还是标签路由,筛选流程以及交集计算流程依然存在大量遍历操作带来算力损耗。首先引入缓存减少遍历。

 

对于标签路由,可以对提供者节点做如下分类: 带动态标签的节点,带静态标签的节点,未打标签的节点,我们可以提前在建立路由元数据的时候,对不同种类节点进行缓存。

 

我们在标签路由内设置了缓存单元,对上述三类节点,进行了分类缓存。 类似的,在就近路由内,对不同机房的提供者列表,直接进行缓存。 同时,我们以位图形式组织了缓存。

 

以图中请求为例,全量节点为a,b,c至j,10个节点。 在应用级标签路由中共维护四份缓存:有gray1,gray2,静态标签位图,无标签位图。类似的,接口级维护两份,分别为grayA标签位图,与无标签位图。最后是就近路由,维护机房级别的位图缓存。

 

请求一从loc1机房发起携带应用级标签gray1,接口级标签garyA。经历应用标签路由与运算,可用列表为a,b,g,经过接口级路由与运算,依然a,b,g。经过就近路由与运算后,只保留ab。由此我们完成了路由执行复杂度从O(n) -> O(1)的挑战。

 

2.缓存一致性

图片

 

我们在路由加入epoch戳,用于缓存版本比对。 消费方发起请求时,会携带最新已经以位图形式储存好的提供方列表,以及对应的epoch戳。每到新一级路由时,新路由会比对自身缓存epoch戳与初始epoch是否一致。 如果一致,则证明视图是一致的,直接使用自身位图缓存与上一阶段的位图结果进行与位运算。 如果不一致,则证明当前路由缓存待更新,那么会直接实时用最新路由配置规则与上一阶段的计算的位图结果进行遍历计算。

 

3.主动缓存更新策略

图片

 

在提供方持续发布过程中,消费方持续进行服务引入,服务字典侧会同步刷新最新的Invoker列表,并计算新的epoch戳,并将最新的invoker列表更新通知至路由器,用于提前建立最新缓存,同时路由器更新与服务字典一致的epoch。

 

2.5 路由优化总结

图片

 

  1. vivo通过建设就近路由能力,显著降低了RT敏感性业务的请求延迟,同时增强了业务的可用性与多机房容灾能力。

  2. 针对路由链,我们从两大方向进行了系统性优化: 

    - 精简链路,并新增虚拟分组,减少遍历的算力消耗。 

    - 引入位图缓存结构,大幅加速路由交集计算速度,依托主动缓存更新与 epoch 版本比对机制,保证了缓存视图的强一致性。

 

优化效果: 随着服务提供方规模不断扩大,CPU 使用率和 TPS 性能提升效果愈发显著。在两千节点规模下,TPS 提升超100%,CPU 利用率也降低27%

 

三、Dubbo负载均衡扩展及优化

在一次RPC调用经过路由筛选后,消费者端必须从多个服务实例中,选择一个节点来发起请求。这个选择策略,可能直接影响了系统的吞吐量、响应延迟、资源利用率等核心指标。 而Dubbo的负载均衡器,正是承担这一关键决策的核心组件。

 

3.1 Dubbo负载均衡优化背景介绍

图片

 

在vivo的互联网业务高速发展过程中,由于持续引入了不同年份、不同供应商的服务器,并考虑到摩尔定律的影响,这些服务器之间存在显著的算力差异。 尽管各实例接收的流量基本一致,但在业务高峰期,实例间CPU利用率表现出明显的不平衡现象。 该现象导致业务集群暴露出若干问题:如整体集群算力利用不充分,低算力机器因负载过高易引发超时,并且频繁触发负载告警被迫人工干预等。

 

备注: 可以看到Dubbo内置自适应负载策略,它的理念是能够基于服务端的多个实时指标,动态计算节点负载,并选择空闲节点进行调用,实现智能化的弹性负载调度。 但是这里需要说明,vivo建设自适应策略时期较早,同期开源社区自适应策略尚处于提案阶段,只存在初始的社区讨论版本。后续vivo对于自适应策略能力的分析与增强是基于此原始版本思路的进行的。当前开源社区已经提供了正式版本,与vivo实现和原始实现有较大差异。

 

3.2 社区讨论版自适应负载均衡

3.2.1 社区讨论版自适应负载均衡技术方案

图片

 

原始方案流程由3部分构成。

  1. 提供方更新自身CPU利用率,每次指标随RPC结果返回。

  2. 消费方异步计算提供方负载,并对负载进行更新并缓存。

  3. 消费方使用P2C算法,这里对P2C做一个简单的介绍:每次负载均衡随机挑选两个节点,并直接选择负载较小的那个节点进行调用。

 

右侧是消费方采用的埋点指标,包括提供方cpu负载,响应时间等参数。 下边是消费方基于采集指标对负载计算的公式 可以直接简易理解为消费方计算的提供方实例负载值,与实例CPU负载值,在途请求数,RT,呈正相关;与请求成功率,权重配置值呈负相关。

 

3.2.2 社区讨论版自适应负载均衡压测结果

图片

 

从结果可以看出,自适应策略使不同算力的机器在流量承载上出现清晰分层,体现了算法基于节点负载进行动态流量调度的有效性。 但也观察到,该版本中CPU利用率存在明显波动,此行为可能会引入服务质量风险。初步分析,利用率震荡原因可能是流量调整机制尚未实现平滑过渡。

 

3.2.3 社区讨论版波动原因分析

图片

 

以最简单的双节点场景为例:假设存在节点 P1 和 P2。 初始阶段,P2 负载较高。在提供方将更新的负载指标返回之前,消费方持续将请求集中发往负载较低的 P1,导致 P1 的负载迅速升至峰值,而 P2 此时无调用,负载掉入极低水平。 随后,消费方更新了负载数据,两个节点的负载视图状态发生反转,以此循环往复。

 

基于上述分析,我们可以从两个关键方向着手优化:

  1. 改进 P2C 的流量分配机制,避免节点在短时间内被集中访问;

  2. 是增强指标平滑流转能力,抑制短期抖动带来的决策干扰,从而提升系统的整体稳定性。

 

3.3 vivo版自适应负载均衡优化

图片

 

  • 对P2C的流量分发策略进行调整:原有的机制是一种“赢者通吃”的模式:算法直接将流量全部导向了当前负载最低的节点。 P2C过程会根据节点的负载计算概率系数,负载低的节点被选中的概率更高,但负载高的节点也不会像之前一样被被完全忽略。这一改进不仅从根源上消除了所有流量瞬间涌向同一节点所带来的震荡风险,也显著提升了集群资源的整体利用率,实现了P2C节点间负载的“削峰填谷”。

 

  • 将负载计算与负载调度分离。如图所示,负载均衡引入了一个独立的权重计算单元。该单元的核心目标是维护一个稳定的、全局的、流量调度视图。 它的设计思路是:消费方根据负载值,计算一个平滑的,连贯变化的虚拟权重,从而间接通过此虚拟权重,使得当前的流量分配过程始终保持稳态。

 

  • P2C过程将基于上述虚拟权重进行节点选择。

 

3.4 vivo自适应负载均衡压测效果展示

图片

 

左侧从左至右依次展示了随机算法、原始版本自适应策略,以及vivo内部优化后的自适应策略,在双算力配置集群的压测环境中的压测表现: vivo优化版本不仅实现了更优的流量分层,还将各节点CPU利用率收敛至基本一致的水平,并始终保持稳定,使得集群达成高效、高吞吐且稳定运行的理想状态。

 

右侧呈现了原始策略与vivo版自适应策略,相对随机策略在多项核心指标上的表现,包括TPS、平均RT等,可看出此次优化效果显著,各项指标均有大幅提升。

 

3.5 vivo自适应负载均衡生产环境使用效果

图片

 

 

  • 提升服务容量:在同等集群规模下,新策略可将集群流量吞吐上限平均提升约15%,有效增强了整体集群承载能力。

  • 提升服务质量:推广新策略后,算法在高峰期可有效抑制超时率,请求失败率下降超过50%。

  • 实现有效降本:新算法通过更精准的流量调度,显著节省了CPU资源占用,预计每年可为业务降低百万元级别的计算成本。

  • 优化运维人力投入:新负载策略大幅减少了低算力机器的利用率告警频率。业务方无需在流量高峰期间专门进行集群实例的静态权重调整,减轻了运维负担。

 

四、技术成果

图片

 

在Dubbo路由层面:我们重点解决两大痛点一是路由筛选时的大量遍历操作导致消费端CPU资源浪费,二是跨机房调用对RT敏感业务的性能影响。 

 

针对路由遍历效率问题,我们实施4项优化:

  • 关闭未使用的路由,减少无效计算;

  • 引入位图缓存机制,将路由筛选复杂度从 O(n) 降至 O(1),大幅提升执行效率;

  • 新增分组路由功能,有效减少进入负载均衡模块的实例数量,减轻后续处理压力。

  • 建设就近路由能力,显著提升了跨机房调用的业务体验,提高服务质量。

 

在负载均衡方面:我们原先面临着原静态策略难以适配底层设施差异,导致算力利用率低的问题。为此,我们基于社区版本构建了vivo自适应负载均衡能力,重点优化P2C算法并引入权重计算单元,实现流量自适应与平滑调度,最终显著提升服务容量与质量,同时实现降本和节约人力的目标。

 

五、未来展望

图片

 

最后是vivo对于Dubbo未来在公司内演进的一些计划与思考:

 

  • 推进Dubbo与开源社区版本对齐: 目前公司内部的Dubbo基线版本基于开源社区2.7.*构建,而社区现已演进至3.*版本,社区3.*版本全面支持新一代高性能通信协议,具备更强的云原生特性。那么未来我们也将持续推进vivo内部基线版本升级,引入更多优秀的开源能力与模型,更好地拥抱云原生架构。

 

  • 构建跨语言的统一微服务治理平台: 当前vivo的服务治理能力主要围绕Java和C++技术栈,随着公司业务高速发展,如Go、Python等语言逐渐广泛应用。目前,跨语言服务调用的需求显著增长,同时也带来了技术栈碎片化、治理能力不协同、配置模型不统一、开发认知不一致等挑战。为此,我们计划建设一套标准化的、语言无关的微服务治理平台。该平台将提供统一的服务发现、流量监控、流量治理以及服务观测能力。真正实现“多语言开发,一体化治理”的目标,以降低未来的系统复杂性与运维成本。


文章来源:https://www.cnblogs.com/vivotech/p/19486239
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

上一篇:剑指offer-62、⼆叉搜索树的第k个结点
下一篇:没有了

相关文章

本站推荐

标签云