线上服务变慢,大家的第一反应往往是"是不是 CPU 不够了""加台机器吧"。但真正慢下来的原因千差万别:CPU 可能一点不忙,卡在磁盘 IO 上;磁盘也没问题,是网络在丢包;网络也正常,是应用里一把锁把所有线程堵住了。盲目加机器、换硬件,经常钱花了故障还在。
这篇文章给一套可操作的瓶颈定位方法论:先用 USE 方法建立排查框架,再按 CPU、内存、磁盘 IO、网络、锁竞争五个分层逐一分析,给出对应工具(top/vmstat/iostat/sar/perf/ss),重点讲锁竞争的思路,最后用一个从现象到结论的完整案例把流程串起来。文中数字为经验量级,工具用法以你的系统版本为准。
一、先立规矩:先测量,后优化
性能优化最大的忌讳是"猜"。凭直觉改配置、加硬件,改完不知道有没有效果,甚至引入新问题。正确顺序是:
- 测量:用数据说明现在慢在哪。
- 定位:找到真正的瓶颈项。
- 假设:提出一个可验证的优化假设。
- 验证:改一处,再测,用数据确认。
- 重复:瓶颈往往不止一个,解决一个会露出下一个。
一次只改一个变量,是性能优化的铁律。
USE 方法:给每个资源三个问题
排查任何资源,都问三件事:
- Utilization(使用率):这个资源有多少时间在忙?低于 60% 通常不是瓶颈,长时间 > 80%~90% 要警惕。
- Saturation(饱和度):有没有请求在排队等待?排队是瓶颈的强信号。
- Errors(错误):有没有报错?错误本身也是瓶颈的表现。
对 CPU、内存、磁盘、网络分别套用,就不会漏。
二、分层定位:五个可能的瓶颈
| 层次 | 典型现象 | 关键指标 | 常用工具 |
|---|---|---|---|
| CPU | 加载慢、响应慢 | us/sy/si 高、runq 长 | top、vmstat、mpstat、perf |
| 内存 | 频繁换页、OOM | free、swap 使用、si/so | free、vmstat、top |
| 磁盘 IO | 读写卡顿 | await、%util、IOPS | iostat、iotop |
| 网络 | 延迟高、丢包、重传 | 带宽、重传、丢包 | ss、sar、netstat、iperf3 |
| 锁竞争 | 多核并发上不去 | sy 高、上下文切换高、CPU 不均 | perf、vmstat、栈分析 |
关键思路:看"谁在等"和"谁在忙"。 真正的瓶颈,是那个"忙不过来、让别的资源都在等它"的资源。
三、工具速查与用法
先把常用工具和它们的"主看什么"记熟:
# 全局第一眼:负载、进程、CPU
top -bn1 | head -20
# CPU 细分 + 上下文切换 + 内存换页(每秒刷新)
vmstat 1
# 每核 CPU 使用率与软中断
mpstat -P ALL 1
# 磁盘 IO:await、%util、IOPS
iostat -x 1
# 系统活动历史/实时(需 sysstat)
sar -u 1 5 # CPU
sar -d 1 5 # 磁盘
sar -n DEV 1 5 # 网络
# 网络连接与状态
ss -s
ss -tan state established | wc -l
# 进程级 IO 占用(需安装 iotop)
sudo iotop -o
# CPU 火焰图/热点函数(需 perf)
sudo perf top
sudo perf record -g -p -- sleep 30
sudo perf report
安装(部分工具需要):
# RHEL / CentOS / Rocky / AlmaLinux
sudo dnf install -y sysstat iotop perf
# CentOS 7
sudo yum install -y sysstat iotop perf
# Debian / Ubuntu
sudo apt update && sudo apt install -y sysstat iotop linux-tools-common linux-tools-generic
各工具的判读要点:
- vmstat 的
r(运行队列) 长期大于 CPU 核数,说明 CPU 排队,CPU 是瓶颈。b列阻塞进程多,往往和 IO 有关。 - vmstat 的
wa(IO 等待百分比) 高,说明 CPU 在等磁盘。 - vmstat 的
si/so非零且持续,说明在换页,内存不够。 - vmstat 的
cs(上下文切换) 异常高(如十万级/秒),结合sy高,多为锁竞争或线程频繁切换。 - iostat 的
await和%util:await 升高、%util 接近 100%,磁盘是瓶颈。 - mpstat 的
%soft:软中断高,通常是网络流量大或网卡中断处理吃满单核。 %sys高、%usr低:多在系统调用、锁、上下文切换上,而非业务计算。
四、锁竞争的分析思路
锁竞争是最"隐蔽"的瓶颈:CPU 看着很忙(%sys 高),但业务吞吐上不去,加核也没用。典型特征:
- 多核没有扩展性:核数翻倍,QPS 不涨甚至下降。
%sys和上下文切换都高:线程在不停争锁、挂起、唤醒。- CPU 使用不均:某个核被锁持有者或调度器占用,其他核在等。
分析步骤:
- 确认并发扩展性:分别用 1、2、4 核压测同一服务,看 QPS 是否随核数上升。若不涨,怀疑锁。
- 看系统指标:vmstat 的
cs高、sy高,r列(运行队列)可能有较多线程争抢。 - 抓火焰图找热点:用 perf 抓取,看栈里是否大量停在锁相关的函数(如 futex、mutex、自旋锁)。
# 采集 30 秒火焰图数据,聚焦该系统调用/锁相关热点
sudo perf record -g -F 99 -p -- sleep 30
sudo perf report --stdio | head -50
# 关注是否有大量时间花在 futex、__lll_lock 等锁相关符号上
-
看应用层:线程池是否过小、是否有全局锁、是否共享可变状态、连接池是否够用。很多"锁竞争"其实来自一把粗粒度的全局锁或串行的单点(如单一数据库连接、单例对象)。
-
优化方向:缩小锁粒度、用无锁结构、分片、减少共享、延长连接池、把串行点并行化。改完必须复测,确认
sy和上下文切换下降、QPS 上升。
五、从现象到瓶颈的定位路径
把上面的东西串成一条可执行路径:
- 看全局:
top/vmstat,判断是 CPU、内存、IO 还是都正常。 - 看是不是 CPU:
r列 > 核数、%usr高 → CPU 密集;%sys/%soft高 → 系统调用/锁/网络。 - 看是不是内存:
si/so持续非零、swap 在用 → 内存不足换页。 - 看是不是磁盘:
wa高、iostat 的await/%util高 → 磁盘瓶颈,再用 iotop 定位是哪个进程。 - 看是不是网络:
%soft高、ss 里连接状态异常、丢包/重传 → 网络瓶颈,用 iperf3、mtr 排查。 - 都不明显但慢:怀疑锁竞争、下游依赖、GC、或压测机自身瓶颈,进入更细的分析(perf、应用日志、下游耗时)。
口诀:先看资源、再看等待、最后看应用。
六、一个完整案例
现象:某接口 QPS 从 3000 掉到 1200,用户抱怨变慢,CPU 使用率却只有 40%。
排查过程:
top:发现 CPU 只用了 40%,但%sys占了 30%,%usr只有 10%,跟"业务计算"不符。vmstat 1:cs(上下文切换)高达十几万/秒,r列长期大于核数,说明线程在频繁争抢。- 怀疑锁竞争:做并发扩展测试,1 核 QPS 1000、2 核 1100、4 核 1200——几乎不涨,强烈提示锁。
perf record -g:火焰图显示大量时间停在锁等待相关的系统调用上。- 应用层定位:找到一处全局配置对象被高频读写,用一把全局互斥锁保护,所有请求串行经过。
- 优化并复测:改成读写锁 + 局部缓存,
cs降到合理水平,QPS 从 1200 恢复到 3500,%sys从 30% 降到 8%。
结论:CPU 不高不代表没瓶颈,得看 CPU 花在哪。%sys 和上下文切换这两个指标,是锁竞争的关键线索。
七、把定位经验沉淀成监控
一次定位解决的是当下,把关键指标沉淀成长期监控,才能提前发现下一个瓶颈。建议把这些指标接进监控告警:
- 资源层:CPU 各维度利用率、内存与 swap、磁盘 await 与 %util、网络带宽与丢包、上下文切换。
- 业务层:QPS、P95/P99 响应时间、错误率、连接数、GC 停顿。
- 关联分析:把业务指标和资源指标放在同一个时间轴上,一旦 QPS 掉、错误涨,能立刻看出是哪一层先动。
监控的价值在于"看见趋势"。等到用户报障才发现,通常已经晚了;指标持续爬升时就该介入,这也是把性能工作从"救火"变成"预防"的关键。
常见问题
Q1:CPU 使用率不高,是不是就没瓶颈?
不是。CPU 不高但慢,瓶颈可能在磁盘、网络、锁竞争、下游依赖或 GC。要看 CPU 的细分(us/sy/si/wa)和等待指标,而不是只看总使用率。
Q2:先优化哪个资源?
先找"饱和并有排队"的那个。用 USE 方法对每个资源看使用率、饱和度和错误,瓶颈通常就是"最忙且有人排队"的那一项。
Q3:vmstat 的 wa 高就一定是磁盘问题吗?
不一定,网络 IO、NFS 挂载卡住也会体现为等待。结合 iostat 的 await/%util 和 iotop 确认到底是哪块设备或哪类 IO。
Q4:上下文切换高怎么办?
先确认是锁竞争还是线程数过多。减少共享、缩小锁粒度、合理设置线程池、避免惊群。然后用 perf 找热点函数。
Q5:定位完一个瓶颈,优化后需要重新定位吗?
需要。解决一个瓶颈后,压力会转移到下一个最弱的环节,可能露出新的瓶颈。优化是迭代过程,要反复测量。
总结
- 性能问题先测量再优化,一次只改一个变量,用 USE 方法(使用率、饱和度、错误)对每个资源排查。
- 分五层看:CPU 看 us/sy/si 和 runq,内存看换页,磁盘看 await/%util,网络看丢包/重传/软中断,锁竞争看 %sys 和上下文切换。
- 工具速查:top/vmstat/mpstat/iostat/sar/ss/iotop/perf,先看资源、再看等待、最后看应用。
- 锁竞争的标志是"多核无扩展性 + %sys 高 + 上下文切换高 + CPU 使用不均",用并发扩展测试和 perf 火焰图定位。
- 方案要落到可验证:改完必须复测,确认指标改善;解决一个瓶颈后要重新定位下一个。
企业QQ咨询




