引言
线上告警响起时,最怕的不是问题复杂,而是手里没有工具、脑中没有路径:CPU 飙高却不知谁在烧、内存泄漏却找不到持有者、磁盘 IO 打满却分不清是应用还是内核。Linux 提供了一整套观测工具,从最底层的 strace 到可视化的火焰图,每一种都对应一类问题。
本文按「方法论 → 工具逐个精讲 → 四类问题排查路径」组织:先建立 USE 模型与「先看全局再看局部」的思路,再依次介绍 strace/ltrace、perf、sysdig/bpftrace、lsof/fuser、tcpdump、sar 与火焰图,最后给出 CPU、内存、IO、网络四类问题的标准排查流程图与命令清单。
前置:Linux 性能监控与调优。进程与调度见 进程管理与 CPU 调度,内存机制见 内存管理与 OOM,eBPF 深入见 eBPF 与可观测性。
目录
- 1. 排障方法论:从现象到根因
- 2. strace 与 ltrace:系统调用与库调用追踪
- 3. perf:CPU 性能分析
- 4. bpftrace 与 sysdig:动态追踪
- 5. lsof 与 fuser:谁占用了资源
- 6. tcpdump:网络抓包分析
- 7. sar 与系统历史数据
- 8. 火焰图:可视化的性能分析
- 9. CPU/内存/IO/网络四类排查路径
- 10. 速查表
- 延伸阅读
1. 排障方法论:从现象到根因
排障的核心是「缩小范围」:先用宏观指标定位资源维度,再用微观工具定位具体进程,最后用追踪工具定位代码路径。
现象(慢/卡/报错)
↓
宏观指标:top / vmstat / iostat / sar —— 是哪一类资源?
↓
定位进程:pidstat / lsof / ss —— 是哪个进程/连接?
↓
深入追踪:strace / perf / bpftrace —— 卡在哪一步?
↓
根因(配置/代码/硬件/容量)
USE 模型(Brendan Gregg 提出)是快速体检的框架——对每种资源检查使用率(Utilization)、饱和度(Saturation)、错误(Errors):
| 资源 | 使用率 | 饱和度 | 错误 |
|---|---|---|---|
| CPU | top、mpstat | vmstat 的 r 列、runqlat | dmesg MCE |
| 内存 | free、vmstat | swap 使用、OOM | dmesg OOM |
| 磁盘 | iostat -x 的 %util | await、aqu-sz | dmesg IO error |
| 网络 | sar -n DEV | 丢包、重传 | ss -s、netstat -s |
# 一分钟体检
uptime # 负载
vmstat 1 5 # CPU/内存/IO 概览
iostat -xz 1 5 # 磁盘
sar -n DEV 1 5 # 网络
top -bn1 | head -20 # 进程
一句话:先「哪一类资源」,再「哪个进程」,最后「哪一行代码」——顺序颠倒会让你在错误的层级浪费大量时间。
2. strace 与 ltrace:系统调用与库调用追踪
strace 追踪「程序与内核的对话」,ltrace 追踪「程序与动态库的对话」——服务卡住或报奇怪错误时,它们能看到程序到底在等什么。
# 基本用法
strace ls # 追踪整个程序
strace -p 1234 # 追踪运行中的进程
strace -f -p 1234 # 追踪所有子进程/线程
strace -e trace=open,read,write ls # 只追踪指定系统调用
strace -e trace=network -p 1234 # 只追踪网络相关
strace -T -tt -p 1234 # 显示耗时与时间戳
strace -c ls # 统计各类调用次数与耗时
strace -o out.txt -p 1234 # 输出到文件
strace -s 256 -p 1234 # 字符串最大显示长度
| 选项 | 作用 |
|---|---|
-p PID | 附加到进程 |
-f | 跟随子进程/线程 |
-e trace= | 过滤系统调用类别 |
-T | 显示每个调用耗时 |
-c | 汇总统计 |
-s N | 字符串截断长度 |
-y | 显示文件描述符对应的路径 |
# 典型场景:服务卡住,看它在等什么
strace -f -T -tt -p $(pidof nginx) 2>&1 | grep -E '<[0-9.]+>' | sort -t'<' -k2 -rn | head
# 典型场景:找不到文件
strace -e trace=openat,stat -f ./app 2>&1 | grep -i 'ENOENT'
# 典型场景:库函数调用(ltrace)
ltrace -p 1234
注意开销:strace 会显著拖慢目标进程(尤其在 -f 下),生产环境慎用,且务必限定时间:
timeout 5 strace -f -p 1234 -o /tmp/trace.txt
一句话:「卡在哪」用
strace -T找耗时最长的调用,「为什么失败」用strace -e trace=...找返回-1的调用——ENOENT、EACCES、ECONNREFUSED往往就是根因。
3. perf:CPU 性能分析
perf 是内核自带的性能分析器,采样调用栈、统计硬件事件,是定位「CPU 被谁吃掉」的首选。
# 顶层视图:实时看热点函数
perf top
# 记录采样
perf record -F 99 -a -g -- sleep 30 # 全系统采样 30 秒
perf record -F 99 -p 1234 -g -- sleep 30 # 只采样某进程
# 查看报告
perf report
# 统计事件
perf stat -p 1234 sleep 5
perf stat -e cycles,instructions,cache-misses,context-switches -a sleep 5
| 子命令 | 作用 |
|---|---|
perf top | 实时热点 |
perf record/report | 采样与离线分析 |
perf stat | 事件计数统计 |
perf sched | 调度延迟分析 |
perf script | 导出原始样本(供火焰图) |
# 关键事件:判断 CPU 瓶颈类型
perf stat -a sleep 5
# 关注:IPC(instructions per cycle)< 1 说明受限于访存/分支
# cache-misses 高 → 内存访问瓶颈
# context-switches 高 → 锁竞争或调度频繁
# 查看调度延迟(runqlat 的 perf 版)
perf sched record -- sleep 5
perf sched latency
一句话:
perf record -F 99 -g+perf report是 CPU 分析的黄金组合——99Hz 采样、带调用栈,跑 30 秒就能看清热点函数及其调用来源。
4. bpftrace 与 sysdig:动态追踪
bpftrace 用一行脚本挂到任意内核/用户态函数上,sysdig 提供「类 tcpdump 的系统调用流」——两者都是低开销的生产级追踪工具。
# bpftrace:谁在打开文件
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
# bpftrace:CPU 采样 + 内核栈
bpftrace -e 'profile:hz:99 { @[comm, kstack] = count(); }'
# bpftrace:统计各进程的系统调用次数
bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[comm] = count(); }'
# bpftrace:追踪慢 IO
bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
@us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'
# sysdig:抓系统调用流
sysdig # 实时流
sysdig -c topprocs_cpu # CPU 占用 Top
sysdig -c topfiles_bytes # 文件读写 Top
sysdig -c topscalls_time # 最慢的系统调用
sysdig proc.name=nginx and evt.type=open # 过滤
sysdig -w trace.scap # 保存供离线分析
sysdig -r trace.scap -c topconns # 离线:连接 Top
| 工具 | 模型 | 开销 | 适用 |
|---|---|---|---|
| strace | 系统调用追踪 | 高 | 单进程短时排障 |
| perf | 采样 + 事件 | 低 | CPU/调度分析 |
| bpftrace | eBPF 动态插桩 | 低 | 生产级自定义追踪 |
| sysdig | 系统调用流 | 中 | 容器与主机全景 |
一句话:strace 是「一次性手术刀」,bpftrace 是「可编程的探针」——需要长期、低开销、自定义的观测时,优先 bpftrace 而不是 strace。
5. lsof 与 fuser:谁占用了资源
「端口被占用」「文件系统无法卸载」「磁盘空间没释放」——这些问题的答案都在 lsof 和 fuser 里。
# 谁占用了某端口
lsof -i :8080
ss -lntp | grep :8080
# 某进程打开了哪些文件
lsof -p 1234
# 谁在使用某目录(卸载失败时)
lsof +D /mnt/data
fuser -m /mnt/data
# 谁打开了某文件
lsof /var/log/app.log
# 查看已删除但仍被占用的文件(磁盘不释放的经典原因)
lsof | grep deleted
| 需求 | 命令 |
|---|---|
| 端口占用 | lsof -i :PORT / ss -lntp |
| 进程打开的文件 | lsof -p PID |
| 目录被谁用 | lsof +D DIR / fuser -m DIR |
| 文件被谁用 | fuser FILE |
| 网络连接 | lsof -i / ss -tanp |
# 经典问题:删了大文件但磁盘没释放
lsof | grep deleted
# 处理:重启持有该 fd 的进程,或
: > /proc/1234/fd/5 # 截断(谨慎)
# 经典问题:卸载失败
fuser -km /mnt/data # 杀掉占用进程(危险)
umount /mnt/data
一句话:「磁盘满了却找不到大文件」十有八九是
lsof | grep deleted——文件被删除但进程仍持有文件描述符,空间要到进程关闭 fd 才真正释放。
6. tcpdump:网络抓包分析
网络问题的最终手段是抓包:连接不上看三次握手,速度慢看重传与窗口,数据错乱看载荷。
# 抓指定网卡、指定端口
tcpdump -i eth0 -nn port 80
# 抓指定主机
tcpdump -i any -nn host 10.0.0.5
# 抓 TCP 握手/挥手(只看标志位)
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0'
# 写文件供 Wireshark 分析
tcpdump -i eth0 -nn -s 0 -w /tmp/cap.pcap
# 限制数量与文件大小
tcpdump -i eth0 -c 1000 -W 5 -C 10 -w /tmp/cap.pcap
# 显示 ASCII 载荷(调试 HTTP)
tcpdump -i eth0 -nn -A port 80
| 选项 | 作用 |
|---|---|
-i IFACE | 指定网卡(any 为全部) |
-nn | 不做 DNS/端口名解析 |
-s 0 | 抓完整包(不截断) |
-w FILE | 写入 pcap |
-A / -X | ASCII / hex+ASCII 显示 |
-C N -W M | 按 MB 轮转,保留 M 个文件 |
# 排障:看有没有 SYN 无 ACK(服务未监听或防火墙丢包)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
# 排障:看重传(网络质量差)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# 配合 ss 看连接状态
ss -s
ss -tan state time-wait | wc -l
一句话:抓包前先想清楚「过滤条件」——
host/port/tcpflags组合能把 GB 级流量缩到几行;不加过滤地tcpdump在生产上是自找麻烦。
7. sar 与系统历史数据
「昨天这个点也卡吗?」——sar 记录了历史性能数据,是复盘与容量规划的依据。
# 安装与启用(sysstat)
apt install sysstat
systemctl enable --now sysstat
# CPU 历史
sar -u
# 内存历史
sar -r
# 磁盘 IO 历史
sar -b
# 网络历史
sar -n DEV
# 指定日期与时间范围
sar -u -f /var/log/sysstat/sa15 -s 09:00:00 -e 10:00:00
# 每秒采样,共 5 次(实时)
sar -u 1 5
| 选项 | 监控对象 |
|---|---|
-u | CPU 使用率 |
-r | 内存与 swap |
-b | IO 与传输速率 |
-n DEV | 网络接口 |
-n TCP | TCP 连接统计 |
-q | 负载与队列 |
# 关键配置:/etc/sysstat/sysstat
# HISTORY=30 保留 30 天
# COMPRESSAFTER=10 10 天后压缩
# 数据目录
ls /var/log/sysstat/
# 定时采集由 cron/systemd timer 驱动
systemctl list-timers | grep sysstat
一句话:「事后复盘」只有 sar 能回答——top/iostat 只反映当下,sar 保存了历史,是排查「间歇性故障」和做容量趋势分析的唯一依据。
8. 火焰图:可视化的性能分析
火焰图把成千上万条采样栈折叠成一张图:横轴是占比、纵轴是调用深度——一眼看出「谁最宽就是谁最耗时」。
# 1. 用 perf 采样(带调用栈)
perf record -F 99 -a -g -- sleep 30
# 2. 导出折叠栈
perf script > out.perf
# 3. 用 FlameGraph 工具生成
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
./stackcollapse-perf.pl out.perf > out.folded
./flamegraph.pl out.folded > flame.svg
# 或用 perf 内置
perf script report flamegraph
火焰图的读法:
| 特征 | 含义 |
|---|---|
| 横轴宽 | 该函数在采样中出现的比例(越宽越耗时) |
| 纵轴深 | 调用栈深度 |
| 顶部尖峰 | 叶子函数(真正在干活的) |
| 颜色 | 随机,无语义(便于区分相邻帧) |
# 生成 off-CPU 火焰图(分析阻塞/等待)
# 需要 bcc 的 offcputime
offcputime -df -p 1234 30 > offcpu.folded
./flamegraph.pl --color=io --title="Off-CPU" offcpu.folded > offcpu.svg
| 类型 | 回答的问题 | 工具 |
|---|---|---|
| on-CPU | CPU 花在哪 | perf + FlameGraph |
| off-CPU | 为什么在等(阻塞) | offcputime |
| 差异图 | 两次采样哪里变了 | flamegraph.pl –diff |
一句话:on-CPU 火焰图看「谁在烧 CPU」,off-CPU 火焰图看「谁在等」——两者结合才能完整解释「慢」:CPU 不高却慢,答案往往在 off-CPU 图里。
9. CPU/内存/IO/网络四类排查路径
把工具串成「路径」:每类问题都有一条从宏观到微观的固定排查顺序,照着走就不会漏。
CPU 高:
uptime # 1. 负载 vs CPU 核数
top -H -p $(pidof app) # 2. 哪个线程
perf top # 3. 哪个函数
perf record -F 99 -p PID -g -- sleep 30; perf report # 4. 调用栈
内存问题:
free -h # 1. 总量与 swap
vmstat 1 # 2. si/so 换页
ps aux --sort=-%mem | head # 3. 谁占内存
pmap -x PID | tail # 4. 进程内存映射
dmesg | grep -i oom # 5. 是否 OOM
IO 问题:
iostat -xz 1 # 1. 设备 %util / await
pidstat -d 1 # 2. 哪个进程在读写在
iotop -o # 3. 实时 IO 排行
biolatency # 4. IO 延迟分布(eBPF)
网络问题:
ss -s # 1. 连接状态汇总
ss -tanp | head # 2. 谁连了谁
sar -n DEV 1 # 3. 网卡吞吐与丢包
ss -ti # 4. TCP 重传/窗口细节
tcpdump -i eth0 -nn host X # 5. 抓包定位
| 维度 | 第一步(宏观) | 第二步(定位) | 第三步(深入) |
|---|---|---|---|
| CPU | uptime / top | top -H / pidstat | perf / 火焰图 |
| 内存 | free / vmstat | ps --sort=-%mem | pmap / memleak |
| IO | iostat -xz | pidstat -d / iotop | biolatency |
| 网络 | ss -s / sar -n DEV | ss -tanp / ss -ti | tcpdump |
一句话:每条路径都是「宏观指标 → 定位进程 → 深入追踪」三步——记住这个骨架,任何一类问题都能在 5 分钟内锁定方向。
10. 速查表
| 需求 | 命令 |
|---|---|
| 追踪系统调用 | strace -f -T -p PID |
| 统计系统调用 | strace -c -p PID |
| 追踪库调用 | ltrace -p PID |
| CPU 实时热点 | perf top |
| CPU 采样分析 | perf record -F 99 -g -a -- sleep 30 |
| 事件计数 | perf stat -a sleep 5 |
| 自定义追踪 | bpftrace -e '...' |
| 系统调用流 | sysdig -c topprocs_cpu |
| 端口占用 | lsof -i :8080 / ss -lntp |
| 删除未释放文件 | lsof | grep deleted |
| 目录被占用 | fuser -m /mnt |
| 抓包 | tcpdump -i eth0 -nn port 80 -w cap.pcap |
| 历史性能 | sar -u / sar -r / sar -b |
| 火焰图 | perf script | stackcollapse-perf.pl | flamegraph.pl |
| OOM 检查 | dmesg | grep -i oom |
一句话记忆:排障三步走「宏观指标 → 定位进程 → 深入追踪」;CPU 用 perf、内存用 pmap、IO 用 iostat+pidstat、网络用 ss+tcpdump;卡在哪用 strace -T,谁在等用 off-CPU 火焰图。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。