服务器与应用系统性能诊断及调优 - 第3节

一、为什么需要性能分析方法论?

刚开始做性能调优那会,我跟很多人一样。遇到系统慢,就怀疑代码写得烂。抓到哪个模块,就一顿瞎折腾。结果呢?有时候能蒙对,但大多数时候,CPU 分析了一通,发现瓶颈在磁盘。或者换个场景,根本找不到问题在哪。

说白了,没有方法论,性能调优就是无头苍蝇。你得有一套固定的打法,知道从哪下手,下一步该做什么。就像医生看病,得先有诊断流程,不能上来就开药。

我个人习惯,把性能分析方法论分成三个维度:

  • 自上而下 —— 从用户视角往下看
  • 自下而上 —— 从硬件资源往上看
  • USE方法 —— 快速定位资源瓶颈

别急着记。我们一个个讲清楚,配合例子,你就知道什么时候该用哪个了。

二、先搞懂两个核心概念:延迟与吞吐量

在聊方法论之前,得先把这两个词整明白。不然你分析半天,都不知道自己在分析啥。

指标 定义 通俗理解 对应场景
延迟(Latency) 单个请求从发出到完成的时间 点一下按钮,要等多久才出结果 API 响应时间、数据库查询时间
吞吐量(Throughput) 单位时间内系统能处理的请求数 一秒钟能服务多少人 QPS、TPS、带宽利用率

你可能遇到过这种情况:给系统加了缓存,单个请求快了,但整体吞吐量却上不去。原因是缓存锁争用严重,CPU 大量时间花在等待锁上。所以啊,延迟和吞吐量不是简单的正相关。你得综合看。

嗯,这里要注意:调优之前先明确,你到底是要降延迟,还是提吞吐量。这两个方向的操作手法,有时候是冲突的。

三、自上而下法:从用户痛点出发

这是我最常用的方法。尤其是线上问题排查时。

思路是什么?

先把问题框定在“用户可感知”的层面。比如:

  • 首页加载变慢了
  • 下单接口超时了
  • 文件导出要等半天

然后一层层往下剥离。从应用层 -> 服务层 -> 中间件层 -> 操作系统层 -> 硬件层。每一层都问一句:问题在这一层吗?

举个例子,我在项目中遇到过用户反馈“报表查询很慢”,大概要30秒。我开始排查:

  1. 第一层(应用层):检查代码逻辑,发现查询语句写得还算规范,没有明显的循环调用。
  2. 第二层(服务层):看日志,发现请求在排队等待数据库连接。
  3. 第三层(中间件层):检查连接池,最大连接数只有20,但并发请求有40个。找到问题了。

你看,我没一上来就去看 CPU 或者磁盘 I/O。因为用户感知到的问题是“慢”,但我不知道慢在哪。自上而下,就是帮我把搜索范围框定好,避免浪费精力。

适用场景

  • 有明确的用户反馈或报警
  • 问题可复现,且能定位到某个功能模块
  • 整个链路你都有监控工具覆盖

缺点也明显

如果问题根本不在你业务链路上,比如某个基础软件升级导致性能下降,你自上而下查半天,可能都找不到根因。这时候就需要换个思路。

四、自下而上法:从硬件瓶颈开始啃

这种方法比较硬核。适合那些“系统没明显报错,但就是感觉不对劲”的场景。

我会从最底层开始:CPU、内存、磁盘、网络。一层层往上看。

操作流程

第一步:看 CPU —— 跑满了吗?上下文切换高不高?软中断多不多?
第二步:看内存 —— 剩余多少?是否在 swap 换页?
第三步:看磁盘 —— 平均服务时间、队列长度、IOPS 是否异常?
第四步:看网络 —— 带宽使用率、丢包率、连接数。

如果这些硬件层面都没问题,再往上面看:操作系统参数、中间件配置、应用程序逻辑。

一个真实的例子

我记得有次帮客户排查一个奇怪的问题:数据库偶尔会响应慢,但大部分时间正常。从上往下查,应用层没问题,SQL 执行计划也正常。我很头疼。

后来我改用自下而上法。先看磁盘,发现某块盘的队列深度经常飙到10以上,但盘本身是 SSD,理论上不该这么差。再往深挖,发现这块盘和另一台机器的日志盘共享了一个磁盘控制器。对方机器在跑全量备份,把带宽抢光了。

原因找到了。但如果我一直盯着应用层,永远看不到磁盘控制器层面的竞争。

什么时候用?

  • 问题间歇性出现,难以通过用户操作复现
  • 你怀疑是硬件或 OS 层面的问题
  • 手上的监控工具覆盖了底层的指标(sar、iostat、vmstat 等)
避坑指南: 我曾经花了一整天看 CPU 使用率曲线,觉得没什么异常。后来才发现,我一直在看整体的空闲率,而瓶颈出现在某个 CPU 核上的软中断。所以说,看底层指标时,要注意粒度。平均值会骗人。

五、USE方法:一个清单式的神器

这个方法我特别推荐。它简单,而且极其有效。尤其适合面试或者快速排查的时候用。

USE 是三个单词的缩写:

Utilization(使用率) —— 资源有多忙
Saturation(饱和度) —— 还有多少资源可用,或者请求在排队
Errors(错误) —— 有没有错误事件

对于每一个资源,你只需要问三个问题:

  1. 它的使用率高吗?(比如 CPU 90%)
  2. 它饱和了吗?(比如磁盘队列深度 > 2)
  3. 它在报错吗?(比如网络丢包率 > 0)

你看,就这么简单。任何一个资源,只要你发现其中一项异常,大概率就是它了。

一个实际的应用表格

资源 使用率指标 饱和度指标 错误指标
CPU 利用率(%usr + %sys) 负载均值(load average),run queue 长度 —
内存 已用百分比 Swap 使用量、OOM 事件 OOM Killer
磁盘 平均服务时间、IOPS / 理论上限 磁盘等待队列长度 I/O 错误计数
网络 带宽利用率 连接队列溢出、丢包率 重传率、CRC 错误

你在排查时,照着这张表一项项查就行。我建议打印出来贴在工位上。真的,非常有用。

USE方法的精髓

它不关心你的业务逻辑。它只关心资源本身的状态。所以对于“我的系统跟屎一样慢,但就是不知道哪出了问题”这种问题,用它最合适。

我举个完整的例子:

# 检查 CPU
$ top -bn1 | head -5
# 看 load average 是否超过 CPU 核数

# 检查磁盘
$ iostat -x 1 3
# 看 %util 和 avgqu-sz

# 检查网络
$ netstat -s | grep -E "retransmit|overflow|drop"

嗯,就是这样的命令行。跑一遍,基本能锁定问题方向。

六、三种方法的对比与选择

性能分析方法论对比图 自上而下 用户报告问题 ↓ 应用层 Logger/Trace ↓ 服务层 连接池/超时 ↓ 中间件层 配置/锁 ↓ OS层 系统调用 ↓ 硬件层 CPU/MEM 适合:用户可感知的慢 自下而上 硬件指标排查 ↑ CPU 上下文切换 ↑ 内存 Swap/OOM ↑ 磁盘队列深/IOPS ↑ 网络重传/丢包 ↑ 应用层配置 适合:无明确报错的神秘问题 USE方法 三问定乾坤 Utilization ↑ 使用率 Saturation ↑ 饱和度 Errors ↑ 错误率 对每个资源: CPU、MEM、DISK、NET 适合:所有场景的快速第一轮 三种方法不是互斥的,可以在一个 Session 里组合使用

你可能会问:那我到底该用哪个?

我的经验是:先用 USE 方法做快速扫描,再用自上而下或自下而上做深度定位。USE 方法像是一个体检的初筛,查出哪个器官有问题。然后针对性去做 CT(自上而下或自下而上)。

  • 如果问题是 用户明确反馈的,你就从自上而下入手,快速定位到具体代码或配置
  • 如果问题是 隐性的、间歇性的,优先用自下而上,从硬件层面找异常
  • 如果你 完全没头绪,或者线上告警五分钟后才到,先从 USE 方法查一轮,把最明显的资源瓶颈排除掉
一个小技巧: 我每次接手一个新系统,第一件事就是搭建一套 USE 方法的监控仪表盘。把 CPU、内存、磁盘、网络的 U/S/E 三项都画出来。这样时间长了,你一眼就能看出正常基线是什么。一旦偏离,马上能收到预警。

七、总结一下这三种打法

自上而下,就像从楼顶往下走,每层都看看有没有漏水的。适合有明确投诉的场景。
自下而上,是从地下室往上走,检查地基稳不稳。适合那种让人摸不着头脑的“系统抽风”。
USE方法,是个清单检查法。我建议你把它当成每台服务器上的“救命手册”。

你想想看,这套组合拳如果打熟了,遇到性能问题你还会慌吗?