Skip to content

性能调优与排障

1. 这是什么

前面几章学完之后,你大概已经知道 Dubbo 是怎么工作的了。

但一到真实线上环境,问题通常不会按章节来:

  • 某个接口突然超时
  • 某个服务错误率升高
  • 某个 Consumer 越重试越糟
  • 某台 Provider CPU 很高
  • 明明网络通,调用还是慢

这时候就进入了 Dubbo 最实战的一章:

  • 性能调优:让调用更快、更稳、更省资源
  • 排障:当调用出问题时,快速找到真正瓶颈

如果只用一句话概括:

Dubbo 排障不是只看一个报错,而是顺着整条 RPC 链路找哪一层出了问题。


2. 为什么重要

RPC 问题之所以难排,是因为它天然跨多个层次:

  • Consumer 侧配置
  • 注册发现
  • 路由与负载均衡
  • 网络传输
  • 序列化/反序列化
  • Provider 业务执行
  • 线程池
  • 下游数据库/缓存/第三方依赖

所以你看到一个“超时”,背后可能完全不是同一个原因:

  • 可能是网络慢
  • 可能是下游 SQL 慢
  • 可能是线程池满了
  • 可能是重试把链路拖长了
  • 可能是序列化对象太大

这也是为什么 RPC 排障最忌讳:

  • 一看到超时,就先把超时值调大

因为这常常只是把问题藏起来,而不是解决它。


3. 先建立排障总思路

你可以把一次 Dubbo 调用拆成 6 段:

  1. Consumer 发起调用
  2. 服务发现与选路
  3. 网络发送
  4. Provider 接收并执行业务
  5. Provider 返回结果
  6. Consumer 收到并解析响应

任何一段慢了,最终都可能表现成:

  • 超时
  • 错误率高
  • RT 飙升

所以排障时不要只问:

  • “这个接口为什么超时?”

而要进一步追问:

  • “它到底慢在链路哪一段?”

这个思路非常关键。


4. 最常见问题 1:超时

超时是 Dubbo 排障里最常见的表象之一。

但“超时”不是根因,只是结果。

常见根因可能包括

  • Provider 业务逻辑慢
  • 下游数据库查询慢
  • Provider 线程池积压
  • 网络抖动
  • 请求体/响应体过大
  • 重试叠加导致总耗时过长
  • Consumer 超时配置过小

一句实战经验

先找哪段慢,再决定调不调超时;不要先调超时,再假装问题解决。


5. 最常见问题 2:重试放大故障

很多系统在下游开始抖动时,会出现一种典型现象:

  • 本来只是少量请求变慢
  • Consumer 开启重试后
  • 请求数被放大
  • 下游更扛不住
  • 最后整个链路一起雪崩

这就是所谓的“重试放大问题”。

例如:

  • 原本 1000 QPS
  • 每个失败请求再重试 2 次
  • 实际打到下游的流量可能瞬间变成数倍

所以重试不是默认收益,而是默认带风险。

特别是:

  • 下游本来就已经慢
  • 线程池已经拥堵
  • 数据库已经告警

这时继续重试,往往是火上浇油。


6. 最常见问题 3:线程池和请求积压

Provider 侧如果线程池满了,会出现什么?

  • 新请求排队
  • 响应时间变长
  • 超时增多
  • CPU 未必很高,但整体调用已经很差

这是很多人容易误判的点。

有些时候问题不是:

  • 机器不行

而是:

  • 线程模型不合适
  • 队列太长
  • 任务执行时间太久

所以看 Dubbo 性能时,不能只看:

  • CPU
  • 内存

还要看:

  • 线程池活跃数
  • 队列积压
  • 请求等待时间

7. 最常见问题 4:序列化和数据体积

很多人排查慢调用时,只盯业务代码,却忽略:

  • 请求对象是不是太大
  • 返回对象是不是太复杂
  • 序列化是不是很重

例如:

  • 一个接口返回几十 KB、几百 KB 的对象
  • 嵌套层级很多
  • 字段冗余严重

这会带来:

  • 序列化成本升高
  • 网络传输时间增加
  • 反序列化更慢

所以优化 RPC 不一定只是优化 SQL,有时候也要先问:

  • 这个对象真的要传这么多字段吗?

8. 最常见问题 5:网络没断,但就是慢

RPC 问题不一定是“网络不通”,更常见的是:

  • 网络可通
  • 但延迟高
  • 或有抖动
  • 或跨机房路径不合理

表现通常是:

  • 偶发超时
  • RT 波动很大
  • 同一接口时好时坏

所以排障时不能只问:

  • ping 通不通

还要看:

  • 延迟是否稳定
  • 是否跨机房
  • 是否有丢包/抖动

9. 一套最实用的排障顺序

以后你遇到 Dubbo 问题,我建议优先按这个顺序排:

第一步:先确认现象

先弄清楚是:

  • 全量失败
  • 部分失败
  • 偶发失败
  • 全部变慢
  • 只有某个 Consumer 慢
  • 只有某个 Provider 慢

不要一上来就进入猜测。

第二步:看关键指标

重点看:

  • QPS
  • RT
  • 超时数
  • 错误率
  • 重试次数
  • 线程池活跃数
  • Provider 实例数

第三步:缩小范围

判断问题更可能在:

  • Consumer 侧
  • 网络侧
  • Provider 侧
  • 下游依赖侧

第四步:结合日志和调用链

例如看:

  • 哪个时间点开始变差
  • 是否刚好发生扩容/发布/配置变更
  • 哪个方法最慢
  • 是否出现线程池拒绝、序列化异常、连接异常

第五步:最后再决定怎么调优

是要:

  • 调超时
  • 改重试
  • 减小对象体积
  • 扩容实例
  • 优化 SQL
  • 改线程池参数
  • 做限流/降级

这个顺序比“直接调参数”可靠得多。


10. 一个典型案例:接口超时,先看哪

假设现象是:

  • queryUserProfile 接口超时率突然升高

建议先这样查:

  1. 是所有 Consumer 都超时,还是某几个超时?
  2. 是所有 Provider 都慢,还是某一台慢?
  3. 最近有没有发布、扩容、配置变更?
  4. Provider 线程池有没有积压?
  5. Provider 下游数据库是不是变慢了?
  6. Consumer 有没有配置重试,导致整体耗时被放大?

这套问法能帮你很快从“一个表象”拆到“一个具体层次”。


11. 调优时最值得优先做的事

很多人一说调优,就想直接改框架参数。

但实际最有性价比的优化,常常是这几类:

11.1 先减无效数据传输

  • 减少不必要字段
  • 避免超大 DTO
  • 避免层层嵌套返回

11.2 先优化下游慢点

  • SQL
  • Redis
  • 外部 HTTP 接口
  • 文件/磁盘 I/O

因为很多 Dubbo 慢,本质不是 Dubbo 慢,而是:

  • Dubbo 背后的业务执行慢

11.3 合理设置超时和重试

  • 不是越大越安全
  • 不是越多越可靠

11.4 观察线程池与并发模型

  • 是否积压
  • 是否拒绝
  • 是否存在长尾任务拖住线程

11.5 监控必须先补齐

如果没有:

  • RT
  • 错误率
  • 超时率
  • 实例维度指标
  • 调用链路追踪

那所谓调优很容易变成拍脑袋。


12. 最容易踩的坑

12.1 请求慢就一味增大超时

这几乎是最常见误区。

超时调大后,用户可能只是更晚失败,系统资源还会被占更久。

12.2 下游已经抖动,还继续加重试

这会把局部问题放大成系统问题。

12.3 不区分“偶发慢”和“持续慢”

偶发抖动和稳定性故障,排查思路不完全一样。

12.4 只盯 Dubbo,不看业务执行

很多问题最终根因在:

  • SQL
  • 缓存击穿
  • 线程阻塞
  • 外部依赖过慢

12.5 没有按实例维度看指标

平均值可能很好看,但其中一台机器已经明显异常。


13. 动手演练建议

练习 1:模拟一个慢 Provider

在 Provider 某个方法里加:

java
Thread.sleep(3000);

观察:

  • Consumer RT
  • 超时数
  • 重试行为

练习 2:模拟线程池积压

让 Provider 执行一个慢任务并并发压测,观察:

  • 线程池活跃数
  • 请求排队
  • 平均 RT 与 TP99

练习 3:模拟大对象传输

让接口返回一个明显偏大的 DTO,观察:

  • RT 是否上升
  • 序列化与反序列化是否变慢

练习 4:模拟错误调参

故意把:

  • 超时调很大
  • 重试次数调很多

再观察系统在下游抖动时会不会更差。


14. 自测问题

  • 为什么 RPC 超时常常只是表象而不是根因?
  • 为什么重试有时会让系统更糟?
  • 排查 Dubbo 性能问题时,为什么线程池指标很重要?
  • 为什么要关注请求/响应对象的体积?
  • 遇到慢调用时,为什么不应该先习惯性调大超时?

15. 这一章你至少要带走什么

如果你看完只记住 5 件事,就记下面这 5 件:

  1. Dubbo 排障一定要按链路拆,不要只盯报错表象
  2. 超时常常只是结果,真正问题可能在业务、网络、线程池或重试
  3. 重试和超时要一起看,否则很容易把问题放大
  4. 线程池、对象体积、下游依赖,都是 RPC 调优的高频关键点
  5. 没有监控、日志和调用链,调优大概率会变成猜测

把这套排障思路建立起来,后面你再遇到 Dubbo 调用慢、错误率高、超时飙升,就不会只会“改大超时再试试”了。