性能测试:如何分析 CPU、内存、磁盘、网络瓶颈
性能测试里最常见、也最容易出错的一类结论,就是这种:
- CPU 高,所以瓶颈在 CPU
- 内存高,所以瓶颈在内存
- 磁盘 util 高,所以瓶颈在磁盘
这类说法不是绝对错,但通常太快了。
因为资源“忙”不等于资源已经成为系统主瓶颈。
从真实排障经验看,资源瓶颈分析真正难的不是看监控,而是要回答:
- 这个资源的异常变化,是否真的开始限制系统继续产出
- 它是根因,还是被动结果
- 它和吞吐、尾延迟、错误率之间有没有明确的时间对应关系
所以做资源分析时,最先警惕的不是“某个指标高”,而是“我是不是下结论下得太快了”。
一、CPU 分析不能只看使用率,要先看“它在忙什么”
看 CPU,基本只看总使用率。
这远远不够。
通常至少会同时看:
- user
- system
- iowait
- load average
- 上下文切换
- 线程数
因为这些指标组合起来,才能大致判断 CPU 为什么高。
1. user 高,通常更像业务逻辑或计算消耗
常见于:
- JSON 序列化反序列化
- 加解密
- 复杂计算
- 代码热路径问题
2. system 高,通常要看内核态消耗
常见于:
- 网络包处理
- 系统调用频繁
- 锁竞争激烈
3. iowait 高,通常不能简单说“CPU 高”
这类情况更常见的解释是:
- CPU 没真正忙在算
- 而是在等磁盘或网络 I/O
所以如果只看总 CPU,会把很多 I/O 问题误判成 CPU 问题。
二、CPU 真正成为瓶颈时,通常会伴随几个联动信号
更愿意把 CPU 瓶颈理解为:
CPU 已经成为继续提升吞吐的主要限制因素。
比较典型的联动信号是:
- CPU 接近上限
- 吞吐不再明显上升
- P95 / P99 开始明显恶化
- 线程排队增加
- 错误率开始抬头
如果只有 CPU 高,但吞吐还在健康增长、延迟也没明显变差,那更像是资源被充分利用,而不是主瓶颈。
三、内存分析真正要分清楚“占用高”和“回收失控”
内存问题是另一类极容易误判的地方。
看到内存高,直觉上很容易觉得系统有问题。
但很多服务本来就应该把空闲内存拿去做:
- 缓存
- page cache
- 对象复用
所以光看内存占用高不高,信息量很低。
通常更关注下面这些问题。
1. 内存是不是持续单向上涨
如果在长稳压里出现:
- 请求结束后不回落
- 周期性越涨越高
那就要怀疑:
- 泄漏
- 对象滞留
- 连接不释放
2. GC 是否明显恶化
尤其在 JVM 体系里,内存问题很多时候最先暴露在:
- GC 次数上升
- Full GC 出现
- GC 暂停时间变长
如果 GC 已经明显影响响应时间,那内存问题就不再只是“资源状态”,而已经开始影响业务体验。
3. 堆内、堆外、缓存是否混在一起看
内存分析不够细,只看一个总数。
但真实问题里,堆外内存、页缓存、直接内存、消息缓冲都有可能是关键因素。
四、磁盘瓶颈最容易被低估,因为很多系统不是“打满”,而是“开始等”
磁盘问题不一定表现成非常夸张的写满。
更常见的是它开始拖慢系统,但表面上还没完全打满。
通常会重点看:
- iops
- throughput
- await
- util
- 队列长度
1. await 往往比 util 更有解释力
很多时候 util 已经高了,但真正更说明问题的是 await。
因为 await 上升意味着请求已经开始明显等待磁盘。
2. 写放大和日志 I/O 经常被忽略
项目里非常常见的一种情况是:
- 应用本身业务逻辑不算重
- 但日志刷盘、数据库写入、临时文件落盘叠加后
- 磁盘侧开始明显抖动
这种场景下,如果不把日志和业务写 I/O 拆开看,很容易只看到“系统整体慢”,但找不到真正的触发点。
五、网络瓶颈很多时候不是“带宽打满”,而是链路质量变差
网络问题最容易被简化成一句:
- 带宽够不够
但真实系统里,网络瓶颈常常表现得更隐蔽。
更常看的信号包括:
- RTT
- 重传
- 丢包
- 连接数
- NAT / LB 行为
- 网卡队列
1. 带宽没满,不代表网络没问题
例如:
- RTT 明显升高
- 重传增多
- 短连接过多
- 中间 LB 或防火墙先顶住
这些问题都可能导致系统延迟显著变差,而带宽图本身看起来还不夸张。
2. 网络问题很容易伪装成应用超时
项目里很常见的一种现象是:
- 接口开始超时
- 最常见的直觉判断是应用变慢
但真实根因可能是:
- 下游链路抖动
- 跨机房 RTT 上升
- 中间代理层排队
如果没有网络侧证据,很容易误把网络问题追到业务代码上。
六、资源瓶颈分析里最有价值的,不是看单机,而是看因果顺序
在项目里最常做的一件事,就是对齐时间窗口,看谁先变差。
例如一次压测里,如果顺序是:
- 磁盘 await 先升高
- 随后数据库响应时间抬高
- 然后应用线程开始堆积
- 最后接口 P99 恶化
那问题链路就比较清楚了。
反过来,如果是:
- 应用 CPU 先顶住
- 然后吞吐停止增长
- 接着错误率抬头
那解释方向就完全不同。
所以资源分析不能只盯最终状态截图,要尽量看变化顺序。
七、在项目里最常见的几个资源误判
误判 1:CPU 高就一定是 CPU 瓶颈
很多时候只是资源利用率高,或者在等 I/O。
误判 2:内存高就要先扩容
如果只是缓存吃满空闲内存,扩容未必是最优先动作。
误判 3:磁盘 util 高就一定是主因
要看它是不是和延迟恶化同步出现,还是只是跟随性波动。
误判 4:网络没打满就说明没问题
很多网络问题根本不是靠带宽图发现的。
八、更常用的资源瓶颈分析顺序
1. 先看吞吐和延迟拐点
先找到系统开始退化的时间窗口。
2. 再在同一时间窗口对资源图做对齐
看:
- CPU
- 内存
- 磁盘
- 网络
九、如果现场让我只带几条命令,通常会带这些
资源分析不能只靠监控大盘。
一旦进到现场排查,通常会补几组系统命令,把“图上的异常”落到机器视角。
例如 Linux 机器上,我最常用的是:
1 | mpstat -P ALL 1 |
这些命令各自回答的问题很明确:
mpstat看 CPU 各核和iowaitpidstat看进程级 CPU、内存、I/Oiostat看磁盘await、utilsar -n DEV看网卡流量和错误ss -s看连接堆积和 socket 状态top -H看线程级热点
如果图上已经出现退化,这几条命令通常能帮你确认它到底落在哪一层。
十、在项目里常用的一套资源排查记录法
为了避免现场只剩零散截图,通常会同步记一张排查表:
| 时间窗口 | 现象 | CPU | 内存 | 磁盘 | 网络 | 初步判断 |
|---|---|---|---|---|---|---|
| 20:10-20:15 | P99 抬高 | user 82% | 稳定 | await 低 | 正常 | 偏 CPU 热点 |
| 20:16-20:20 | 吞吐停滞 | user 78% | 稳定 | await 升高 | 正常 | 磁盘等待开始出现 |
| 20:21-20:25 | 错误率上升 | user 76% | 稳定 | await 高 | 正常 | 磁盘成为主限制 |
这张表最大的作用,是强迫自己按时间顺序解释问题,而不是看到最后一张图才倒推原因。
十一、一次典型排查里怎么判断根因和伴生现象
例如现场看到:
- CPU 80%
- P99 变差
- 磁盘 await 明显上升
这时候不能立刻下结论说“CPU 是瓶颈”。
通常会继续追两个问题:
- CPU 高是在问题前出现,还是在问题后出现
- 吞吐停滞更早跟谁同步,CPU 还是磁盘等待
如果顺序是:
- 磁盘 await 先升
- 数据库响应变慢
- 应用线程开始堆积
- CPU 才跟着升
那 CPU 更像伴生现象,不该当成主因去优化。
谁最先出现异常变化。
3. 再看更细一级的证据
例如:
- JVM / GC
- SQL 等待
- Redis 延迟
- 网卡重传
- 磁盘 await
4. 最后再下瓶颈结论
这样结论会比“看一张资源图就拍板”稳很多。
结语
资源瓶颈分析最怕的,就是把“谁高”直接等同于“谁有罪”。
真正有效的判断,应该建立在三件事上:
- 这个资源是否开始限制系统继续产出
- 它和吞吐、延迟、错误率之间有没有明确联动
- 它是根因,还是被动结果
只有把这些关系理顺,CPU、内存、磁盘、网络的分析才真正有排障价值。