Linux 性能优化实战:定位问题,一步步排查 CPU / 内存 / 磁盘 / 网络
作为刚接触 Linux 运维和系统编程的本科生,我第一次被派去排查"服务器变慢"时,是手足无措的------不知道先看什么、用什么命令、看出来的数字什么意思。
这篇博客把我踩坑后整理出来的排查思路和常用工具,讲清楚:遇到性能问题,先做什么、再看什么、最后怎么定位。
这篇博客你能收获什么
- 建立"先测量、再优化"的正确思路,不再凭感觉瞎猜
- 掌握一套通用的性能排查方法论(USE 方法 + 60 秒检查法)
- 会用
uptime/top/vmstat/mpstat/iostat/free/ss/sar等核心命令 - 看懂 CPU、内存、磁盘、网络四大类指标分别代表什么问题
- 走完一个完整的"服务器变慢"排查实战案例
适用人群
- 会用 Linux 基本命令(
ls/cd/ps),但没做过性能排查的同学 - 课程设计、社团服务器、个人云服务器出了问题不知道怎么查的同学
- 准备面试被问"系统卡了怎么排查"的同学
准备一台 Linux 环境
- 本机装个 Linux 虚拟机,或者买/租一台便宜的云服务器都行
- 下面大部分命令自带;
mpstat/iostat/sar属于sysstat包,需单独安装:
bash
# Debian / Ubuntu
sudo apt install sysstat
# CentOS / RHEL
sudo yum install sysstat
1. 先改变思路:性能优化 = 先测量,再优化
最容易踩的坑是:一上来就"优化"。比如听说改某个内核参数能提速,就立刻改,结果系统更不稳定了。
性能优化的正确姿势,永远是先回答三个问题:
1. 系统真的慢吗?
2. 慢在哪?
3. 怎么改?
翻译成一句话:没有数据,就没有优化。 盲目的"优化"只是撞大运。
所以本文的路线是:先教你怎么看数据 (工具),再教你怎么读数据 (指标含义),最后给你一套排查流程(实战)。
2. 一套通用的方法论:USE 方法 + 60 秒检查法
2.1 USE 方法:三个字母走天下
这是性能领域大佬 Brendan Gregg(著有《性能之巅》)提出的方法,专门用来回答"系统哪里是瓶颈"。
对系统里的每一种资源(CPU、内存、磁盘、网络),都问三个问题:
| 字母 | 含义 | 通俗解释 | 怎么判断出问题 |
|---|---|---|---|
| Utilization | 利用率 | 资源有多忙 | CPU 忙到 100% |
| Saturation | 饱和度 | 忙不过来了,活儿在排队 | 运行队列排长队、内存开始交换 |
| Errors | 错误 | 有没有出错 | 磁盘报错、网卡丢包 |
一句话记忆:先看资源忙不忙,再看是不是忙到排队,最后看有没有报错。 排队的(Saturation)通常比忙碌(Utilization)更能说明瓶颈。
2.2 60 秒检查法:先拍快照,再下结论
Netflix 性能团队推荐了一个"60 秒快速体检"流程------登录服务器后,用一组基础命令快速掌握全局,再决定往哪个方向深挖。
第 1 步:看整体 → uptime、top
第 2 步:分资源看 → vmstat(CPU/内存)、iostat(磁盘)、free(内存)、ss/sar(网络)
第 3 步:锁定进程 → pidstat、ps
第 4 步:深入根因 → 分析业务代码、系统日志
核心原则:从宏观到微观,从现象到本质。 千万别一上来就 strace、翻日志------先搞清楚"哪条线先失控",范围才会越来越窄。
3. 第一课:看整体------uptime 和 top
3.1 uptime:系统负载的"体温计"
bash
uptime
输出示例:
bash
15:30:10 up 52 days, 3:14, 2 users, load average: 1.20, 0.85, 0.62
重点是最后的 load average,它代表 1 分钟、5 分钟、15 分钟的平均负载。
- 负载 = 正在运行 + 正在等待 CPU 的进程数(近似)
- 单核 CPU:负载 1.0 ≈ 满载;负载长期超过 1.0,说明 CPU 忙不过来了
- 多核机器按核数折算:4 核 CPU,负载到 4.0 才等于满载
速查:
| 现象 | 含义 |
|---|---|
| 1 分钟负载 > 5/15 分钟负载 | 负载正在上升,刚发生或正在发生问题 |
| 15 分钟负载 > 核数 | 系统持续过载,不是瞬时抖动 |
| 负载高但 CPU 使用率不高 | 可能卡在磁盘 I/O 或锁等待(见第 6 节) |
3.2 top:实时全局仪表盘
bash
top
这是最有用的入门命令,按 1 可以展开每个 CPU 核心。重点看前五行:
text
top - 15:31:02 up 52 days, 2 users, load average: 1.20, 0.85, 0.62
%Cpu(s): 12.5 us, 3.2 sy, 0.0 ni, 82.6 id, 1.5 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 15872.0 total, 2048.0 free, 8192.0 used, 5632.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used
%Cpu(s) 各列的含义(必记):
| 字段 | 含义 | 信号 |
|---|---|---|
us |
用户态 CPU 使用率 | 应用自己在干活,正常的主要消耗 |
sy |
系统态 CPU 使用率 | 内核在干活(系统调用、中断等),过高需警惕 |
id |
空闲率 | 越大越空闲 |
wa |
等待 I/O 的时间 | 很高 → 磁盘(或网络)是瓶颈,这是关键信号 |
st |
被虚拟化偷走的时间 | 云服务器被其他租户抢占,可联系云厂商 |
Mem 行重点 :看 used 和 available(free 命令里)而不是 free------因为 buff/cache 是内核缓存,可以随时回收,不是"被占用了"。
记住:
wa高,问题在磁盘;us高,问题在你的程序;sy高,问题在内核或系统调用。
4. CPU 排查:vmstat / mpstat / pidstat
当怀疑 CPU 有问题时,用下面三个命令由粗到细。
4.1 vmstat:一屏看全局
bash
vmstat 1
每秒刷新一次(按 Ctrl+C 退出)。输出示例:
text
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
5 0 0 102400 204800 524288 0 0 12 15 800 1000 30 20 40 10 0
重点看这几列:
| 列 | 含义 | 判断 |
|---|---|---|
r |
正在运行/等待 CPU 的进程数(运行队列) | 长期大于 CPU 核数 → CPU 饱和 |
b |
阻塞在 I/O 上的进程数 | 持续大于 0 → 磁盘 I/O 有问题 |
us / sy |
用户态 / 系统态 CPU | 同 top |
wa |
等待 I/O 的 CPU | 持续偏高 → 磁盘瓶颈 |
si / so |
从磁盘换入 / 换出内存 | 长期不为 0 → 内存不足(见第 5 节) |
4.2 mpstat:看是不是单个核爆了
bash
mpstat -P ALL 1
如果一个多核服务器整体负载不高,但某个核 %usr 接近 100%,说明单个核心成了热点(常见于单线程应用)。这样就能避免被"整体看起来正常"骗过去。
4.3 pidstat:锁定具体进程
bash
pidstat 1
输出每个进程的 CPU 占用,配合 top 里的高占用 PID,可以精准定位"是谁在吃 CPU"。
bash
pidstat -p PID 1 # 只看某个进程
pidstat -t 1 # 按线程看(排查多线程应用)
CPU 排查小结 :
vmstat看整体 →mpstat看核心 →pidstat定位进程。us高先怀疑应用,sy高怀疑系统调用,wa高直接跳到磁盘排查。
5. 内存排查:free / vmstat
5.1 free:看内存到底够不够
bash
free -h
输出示例:
text
total used free shared buff/cache available
Mem: 15Gi 8.0Gi 2.0Gi 300Mi 5.5Gi 7.3Gi
Swap: 2.0Gi 0.0Gi 2.0Gi
新手最容易误解的一点:used 高 ≠ 内存不够。
buff/cache是 Linux 拿空闲内存做的磁盘缓存 ,是为了加速读取,随时可以被回收给程序用- 判断内存是否紧张,看
available(真正可用的内存),而不是free - 只有
available接近 0,同时开始大量使用Swap,才是真的内存不足
5.2 vmstat 的 si/so:内存告急的信号
回到 vmstat 1:
si(swap in):从磁盘换入内存so(swap out):从内存换出到磁盘
如果 si / so 持续不为 0,说明内存真的不够了,系统正在频繁"倒腾"数据到磁盘,这是很伤性能的。此时思路应该是:加内存、或排查哪个进程内存泄漏。
bash
# 顺便看看哪些进程吃内存最多
top -o %MEM # 按内存占用排序
ps aux --sort=-%mem | head
6. 磁盘 I/O 排查:iostat / iotop / df
当 top 里的 wa 很高时,问题基本就在磁盘。
6.1 iostat:磁盘有多忙
bash
iostat -xz 1
输出示例(每设备一行):
text
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
sda 20.0 30.0 1024.0 2048.0 0.0 0.0 0.0 0.0 12.0 15.0 0.50 51.2 68.2 8.00 40.0
新手看两个指标:
| 指标 | 含义 | 信号 |
|---|---|---|
%util |
设备忙的时间占比 | 接近 100% → 磁盘快成瓶颈 |
await |
平均 I/O 等待时间(毫秒) | 明显变大 → 磁盘响应慢 |
注意:SSD / 云盘瞬时能力很强,
%util100% 不一定代表慢,要结合await一起看。
6.2 iotop:谁在疯狂读写
bash
sudo iotop
实时显示每个进程的磁盘读写速度,用来锁定"是哪个进程在狂写磁盘"(比如日志刷太频繁、数据库没开缓冲)。
6.3 df / du:磁盘是不是满了
bash
df -h # 看各分区使用率,满了会引发各种诡异问题
du -sh /var/log/* | sort -rh | head # 找大文件,优先查日志
磁盘满会导致程序无法写日志、数据库无法落盘,表现经常是"莫名卡死"。排查性能问题前,先确认磁盘没满。
7. 网络排查:ss / sar / ping
7.1 ss:连接状态一览
bash
ss -antp
替代老旧的 netstat,列出所有 TCP 连接及其状态。重点看异常状态:
| 状态 | 含义 | 风险 |
|---|---|---|
SYN_RECV |
连接请求堆积 | 可能被攻击(SYN Flood)或服务处理不过来 |
TIME-WAIT |
连接关闭等待 | 过多会占满端口,需调优 |
ESTAB 异常多 |
活跃连接过多 | 可能连接泄漏 |
bash
ss -s # 统计摘要,一眼看各状态数量
7.2 sar:看网卡流量和丢包
bash
sar -n DEV 1 # 每秒看网卡收发流量
sar -n EDEV 1 # 看网卡错误和丢包(errors / drops)
如果 rxkB/s / txkB/s 接近网卡带宽上限,就是带宽打满 ;出现大量 drop,说明网卡或内核队列处理不过来。
7.3 延迟排查
bash
ping -c 4 目标IP # 看基础延迟和丢包
ping -c 4 -s 1400 目标IP # 用大包测,排查 MTU 问题
8. 实战案例:服务器突然变慢怎么办
把前面所有知识串成一个完整流程。场景:你管理的服务器最近响应很慢,用户开始抱怨。
第 1 步:拍快照,看整体(60 秒内)
bash
uptime
top
发现:
text
load average: 8.50, 6.20, 3.10 # 负载持续上升,且远超核数
%Cpu(s): 5.0 us, 2.0 sy, 0.0 ni, 10.0 id, 82.0 wa, ...
关键信号:wa 高达 82%,说明 CPU 大量时间在等磁盘 I/O------瓶颈很可能在磁盘,而不是 CPU。
第 2 步:确认瓶颈类型
bash
iostat -xz 1
vmstat 1
看到某块盘 %util 长期 100%、await 飙升,同时 vmstat 的 b(阻塞进程)持续不为 0。实锤:磁盘 I/O 瓶颈。
第 3 步:锁定元凶进程
bash
iotop # 看谁在狂读写
pidstat -d 1 # 按进程看磁盘读写
发现某个应用在疯狂写日志,或者数据库在频繁刷盘。
第 4 步:分析根因并解决
常见根因与对策:
| 根因 | 对策 |
|---|---|
| 日志刷太频繁 / 日志过大 | 调日志级别、加日志轮转(logrotate) |
| 数据库未合理用缓冲 / 慢查询多 | 优化 SQL、加大 buffer、加索引 |
| 单盘性能不足 | 换 SSD、加缓存层、多盘负载均衡 |
| 代码反复读写大文件 | 优化代码,减少不必要的 I/O |
第 5 步:验证
bash
uptime && top # 再看负载是否回落、wa 是否下降
优化完一定要回到同一批命令复测,用数据确认问题解决了,而不是"感觉好多了"。
9. 常见优化手段(先确认瓶颈,再动手)
再次强调:先定位瓶颈,再优化。 在不知道瓶颈在哪的情况下调参,等于蒙眼修车。
9.1 几个常见的内核参数(改前先备份、先小范围试验)
| 参数 | 作用 | 何时考虑调 |
|---|---|---|
vm.swappiness |
控制系统多"愿意"用 Swap | 内存充足但频繁换页时,可从默认值调低(如 10) |
fs.file-max / ulimit -n |
文件描述符上限 | 服务报 "too many open files" 时 |
TCP 相关(net.ipv4.tcp_tw_reuse 等) |
加速 TIME-WAIT 连接回收 | ss -s 显示 TIME-WAIT 过多时 |
bash
# 临时修改(重启失效):
sudo sysctl vm.swappiness=10
# 永久修改:写入 /etc/sysctl.conf 后执行
sudo sysctl -p
9.2 更重要的"优化"其实是这些
- 代码层面:减少无效 I/O、避免不必要的锁、用缓存
- 架构层面:加缓存(Redis)、读写分离、水平扩容
- 资源层面:升级配置、换 SSD、加内存
对入门阶段来说:先学会"测量",把慢的原因找对,比急着调参数重要得多。
10. 进阶方向:下次想看更深的
入门掌握上面这些工具后,如果还想深入,可以了解这几个方向(本篇不展开):
- perf :Linux 自带的性能剖析工具,可以看 CPU 时间都花在哪个函数上(
perf top、perf record/report) - 火焰图(Flame Graph):把 CPU 栈采样可视化,一眼看出热点函数
- eBPF / bpftrace:现代内核观测技术,可以在不修改程序的情况下动态追踪(内核 4.4+ 支持)
- strace:追踪进程的系统调用,排查"程序卡在哪个系统调用上"
11. 总结:一张图 + 一套命令
性能问题
│
▼
第 1 步 看整体 ──► uptime(负载) / top(wa、us、Mem)
│
▼
第 2 步 分资源 ──► CPU: vmstat / mpstat / pidstat
│ 内存: free -h / vmstat(si/so)
│ 磁盘: iostat / iotop / df
│ 网络: ss / sar / ping
│
▼
第 3 步 锁进程 ──► pidstat / iotop / top 排序
│
▼
第 4 步 找根因 ──► 日志 / 业务代码 / 配置
│
▼
第 5 步 优化+验证 ─► 改完用同一批命令复测
三句话记住本文核心:
- 先测量,再优化------没有数据就没有优化,别凭感觉乱调参数。
- 看指标有规律 ------
wa高看磁盘、us高看应用、si/so高看内存、drop高看网络。 - 排查有套路------先整体后局部,先定位瓶颈再动手,改完必须复测验证。
性能优化不是玄学,而是一套"测量 → 定位 → 优化 → 验证"的可重复流程。把上面的工具用熟,你已经能解决大多数"服务器变慢"的问题了。
如果这篇博客对你有帮助,欢迎点赞收藏,也欢迎在评论区聊聊你遇到过最诡异的性能问题~
参考资料
- Brendan Gregg《性能之巅》及 USE 方法 --- https://www.brendangregg.com/usemethod.html
- Netflix:Linux Performance Analysis in 60,000 Milliseconds --- https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55
- 常用工具官方文档:
man uptime/man top/man vmstat/man iostat/man free/man ss/man sar