3. 性能度量与监控

性能优化这件事,说白了就是一场「数据驱动的战争」。没有度量,就没有优化。你连瓶颈在哪都不知道,谈何调优?

我个人习惯,接手任何一个系统,第一件事不是看代码,而是先搭监控。把 KPI 拉出来,把工具架起来,跑一遍基准测试。嗯,这一步走稳了,后面才不会抓瞎。

3.1 关键性能指标(KPI)—— 你到底该看什么?

很多新手一上来就盯着 CPU 使用率看,觉得它高了就是有问题。其实不然。我遇到过好几次,CPU 使用率才 30%,但系统已经慢得像蜗牛。为什么?因为瓶颈可能在磁盘 I/O 或锁竞争上。

所以,我们先搞清楚:哪些指标才是真正要命的?

指标类别 具体指标 说明
CPU 用户态时间、系统态时间、空闲时间、上下文切换次数 上下文切换过高,往往意味着锁竞争或线程过多
内存 物理内存使用率、Swap 使用率、缓存/缓冲区大小 Swap 飙高,说明物理内存不够用了,性能会断崖式下跌
磁盘 I/O IOPS、吞吐量、平均 I/O 等待时间(await) await 超过几十毫秒,磁盘基本就是瓶颈了
网络 带宽使用率、丢包率、TCP 重传率 重传率超过 1%,网络质量堪忧
应用层 QPS、TP99 延迟、错误率 TP99 是用户体验的底线,比平均值重要得多

核心原则:不要只看平均值。平均值会骗人。比如 TP99 是 200ms,但 TP999 可能是 5s。那 0.1% 的慢请求,可能就搞垮了整个系统的口碑。

3.2 性能监控工具 —— 你的「听诊器」和「CT 机」

工具不在多,在于会用。我见过有人装了十几个监控工具,结果一个都没吃透。其实,把下面这三个玩明白,90% 的性能问题都能定位。

3.2.1 top —— 老牌经典,但别只会看 CPU

top 命令,几乎每个工程师都用过。但大多数人只盯着 %CPU 那一列看。你想想看,这其实浪费了 top 一大半的能力。

我个人习惯,打开 top 后,先按 1 看每个 CPU 核心的负载分布。如果某个核心跑满,其他核心空闲,那大概率是单线程瓶颈。再按 P 按 CPU 排序,按 M 按内存排序,快速找到「罪魁祸首」。

# 常用操作
top -H -p <PID>   # 查看某个进程的所有线程,看哪个线程在吃 CPU

小技巧:我曾经排查过一个诡异问题,CPU 不高但系统响应慢。用 top -H 一看,发现有个线程在疯狂做上下文切换。原来是锁粒度太粗,导致大量线程在空转。把锁拆细后,问题立刻解决。

3.2.2 htop —— top 的「可视化升级版」

htop 比 top 更直观。它用颜色区分 CPU 状态:绿色是用户态,红色是内核态,蓝色是低优先级。一眼扫过去,就能知道系统在忙什么。

我最喜欢 htop 的一点是,它支持鼠标操作。你可以直接点选进程,按 F9 发送信号。嗯,调试时特别方便。

# 安装 htop(如果系统没有)
sudo apt install htop   # Ubuntu/Debian
sudo yum install htop   # CentOS/RHEL

注意:htop 默认不显示线程。你需要按 Shift + H 切换到线程视图。否则,你可能会漏掉某个线程的异常行为。

3.2.3 perf —— 性能分析的「核武器」

如果说 top 和 htop 是听诊器,那 perf 就是 CT 机。它能深入到 CPU 指令级别,告诉你代码到底慢在哪一行。

我记得有一次,一个算法模块跑得特别慢。用 top 看,CPU 吃满了,但不知道在干什么。用 perf record 采样后,发现 70% 的时间花在了一个 memcpy 上。原来是一个临时变量没用好,导致大量内存拷贝。改了一行代码,性能提升 3 倍。

# 基本用法
perf record -g -p <PID>   # 采样,-g 表示记录调用栈
perf report               # 分析结果,看热点函数

避坑指南:我曾经在虚拟机上用 perf,结果采样结果全是乱码。后来才发现,虚拟机里的 perf 事件映射有问题。所以,性能分析尽量在物理机或裸金属容器里做,数据才可信。

3.3 性能基准测试 —— 给系统「称体重」

基准测试的目的,就是给系统一个「初始分数」。你优化前跑一遍,优化后跑一遍,对比一下,才知道有没有效果。

我个人习惯,基准测试要满足三个条件:

  • 可重复:同样的环境、同样的参数,跑出来的结果应该差不多。
  • 有压力:别只测 1 个并发用户。要测到系统扛不住为止,才能看到拐点。
  • 有指标:不要只测吞吐量,还要测延迟。吞吐量高但延迟爆炸,那也没用。

3.3.1 常用基准测试工具

工具 适用场景 示例命令
ab (Apache Bench) HTTP 接口压测 ab -n 10000 -c 100 http://localhost/
wrk HTTP 接口压测(更现代) wrk -t12 -c400 -d30s http://localhost/
sysbench CPU、内存、磁盘、数据库压测 sysbench cpu run
fio 磁盘 I/O 性能测试 fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --bs=4k --iodepth=64 --size=1G --readwrite=randread

经验之谈:用 ab 压测时,注意它默认是短连接。如果你的服务是长连接,ab 的结果会偏悲观。这时候用 wrk 更合适,它支持 keep-alive。

3.3.2 基准测试的「黄金法则」

跑基准测试时,有几点一定要注意:

  • 预热:很多系统有 JIT 编译或缓存。不预热直接测,结果会偏低。我一般先跑 10% 的请求,再正式记录数据。
  • 隔离:测试机器上不要跑其他负载。否则结果里混了别人的噪音,你根本分不清是优化有效还是运气好。
  • 多次取中位数:跑 5 次,去掉最高和最低,取中间 3 次的平均值。这样能排除偶然波动。

警告:千万不要在生产环境直接跑压测!我曾经见过有人把压测流量打到了线上数据库,结果直接把库打挂了。基准测试一定要在预发或隔离环境里做。

3.4 知识体系总览

下面这张图,是我自己总结的性能度量与监控的完整链路。从指标采集,到工具分析,再到基准验证,环环相扣。

性能度量与监控知识体系 关键性能指标 (KPI) 性能监控工具 性能基准测试 CPU / 内存 磁盘 / 网络 应用层 (QPS/TP99) top htop perf ab / wrk sysbench fio 核心流程:采集指标 → 工具定位 → 基准验证 → 迭代优化 没有度量,就没有优化。先测再说。

好了,这一章的内容就到这里。记住,性能优化不是玄学,是科学。把 KPI 定好,把工具用好,把基准跑好,剩下的就是耐心和细心了。