排查工具箱与命令速查
排查不需要花哨的工具,生产机上常见的 top、vmstat、iostat、ss、lsof、perf 就够覆盖八成场景。本章按资源维度给出命令矩阵与一行判读,并说明发行版自带与不自带的区别、工具缺失时如何用 /proc 兜底。
按维度选用工具
先用一句话概括:CPU 看 top/mpstat,内存看 free/vmstat,磁盘看 iostat/df,网络看 ss/ip,进程内部看 pidstat/strace,内核消息看 dmesg/journalctl。
| 维度 | 首选命令 | 用途 | 一行判读 |
|---|---|---|---|
| 整体 | uptime | load 与运行时长 | 运行时长很短说明刚重启,现场可能已丢 |
| CPU | top | 进程级 CPU 与负载 | %sy 高看 syscall/中断,%wa 高看磁盘 |
| CPU | top -Hp <pid> | 线程级 CPU | 找到最高线程,转十六进制去比对线程栈 |
| CPU | mpstat -P ALL 1 | 每核分布 | 只有个别核满 → 单线程热点或中断绑核不均 |
| CPU | pidstat -u 1 | 进程 CPU 明细 | 拆出 %usr/%system/%iowait |
| 内存 | free -h | 总量与可用量 | 只看 available,不看 free |
| 内存 | vmstat 1 | 交换、上下文切换 | si/so 非 0 说明在用 swap,延迟必然抖 |
| 内存 | pidstat -r 1 | 进程内存明细 | 关注 RSS 是否只涨不跌 |
| 内存 | pmap -x <pid> | 进程内存段 | 看哪一段占大头(堆、映射文件) |
| 内存 | smem -tk -s rss | 按进程实际占用排序 | 区分 PSS 与 RSS,避免重复计算共享内存 |
| 磁盘 | df -h 与 df -i | 空间与 inode | 两个都必须看,报错信息不同 |
| 磁盘 | iostat -x 1 | 设备级 IO | %util 接近 100 或 await 明显升高即饱和 |
| 磁盘 | pidstat -d 1 | 进程级 IO | 找出读写最多的进程 |
| 磁盘 | iotop -oPa | 交互式 IO 排行 | 需 root,看累计写入量最有效 |
| 磁盘 | du -sh /var/log/* | 目录占用 | 日志目录往往是第一嫌疑人 |
| 网络 | ss -s | 连接状态汇总 | 看 estab、timewait、orphan 数量 |
| 网络 | ss -lntp | 监听端口与进程 | 确认服务真的在监听 |
| 网络 | sar -n DEV 1 | 网卡吞吐与丢包 | 带宽打满或丢包上升即网络瓶颈 |
| 网络 | tcpdump -i eth0 -nn port 3306 | 抓包 | 确认是否真的发出了请求、对端是否响应 |
| 进程 | pidstat -w 1 | 上下文切换 | cswch/s 高多为锁等待,nvcswch/s 高为抢占 |
| 进程 | strace -cp <pid> | syscall 统计 | 找耗时或次数异常的 syscall |
| 性能 | perf top -g -p <pid> | 实时热点函数 | 定位用户态 CPU 热点最快的方式 |
| 句柄 | lsof -p <pid> | wc -l | 句柄总数 | 和 ulimit -n 对比看余量 |
| 句柄 | lsof +L1 | 已删除但仍被占用的文件 | 磁盘没释放空间的经典原因 |
| 日志 | dmesg -T | 内核消息 | 查 OOM、磁盘错误、网卡 reset |
| 日志 | journalctl -u myapp --since "10 min ago" | 服务日志 | 按时间窗口捞,不要逐条 grep |
| JVM | jstat -gcutil <pid> 1000 | GC 状态 | 老年代持续接近 100% 且 Full GC 频繁 |
| JVM | jstack <pid> | 线程栈 | 找 BLOCKED 与同一栈反复出现的线程 |
| JVM | jmap -histo:live <pid> | 对象直方图 | 看哪个类实例数与占用异常 |
| DB | SHOW PROCESSLIST / pg_stat_activity | 活动会话 | 找长时间运行的查询与锁等待 |
自带与不自带
| 工具 | 所属包 | 说明 |
|---|---|---|
| top、free、df、du、ss、lsof、ps | 系统自带(procps、util-linux、iproute2 等) | 最小化安装基本都有 |
| vmstat、iostat、mpstat、pidstat、sar | sysstat 包 | 常见精简镜像不带,需要预装 |
| htop、iotop | 额外安装 | 交互体验好,但不是必需 |
| perf | linux-tools / linux-perf 包 | 版本必须与内核匹配,否则报错 |
| strace | 额外安装 | 容器内常缺,且需要 ptrace 权限 |
| bpftrace、bcc 工具集 | 额外安装 | 需要较新内核,适合深挖 runqlat 等 |
| jstack、jstat、jmap | JDK 自带 | JRE 只有运行时,需装完整 JDK |
生产机上装工具的原则:能装就提前装好,故障时现装往往受限于网络与审批。核心机器统一预装 sysstat 并开启数据采集。
工具缺失时用 /proc 兜底
内核暴露的接口永远在,只是不够友好。
| 想要的信息 | 缺工具时的替代 | 关键字段 |
|---|---|---|
| 负载与运行队列 | cat /proc/loadavg | 前三个是 1/5/15 分钟 load,第四个是运行中/总进程数 |
| CPU 各状态占比 | cat /proc/stat | user、system、iowait、irq、softirq、steal |
| 内存详情 | cat /proc/meminfo | MemTotal、MemAvailable、Dirty、Writeback |
| 磁盘 IO | cat /proc/diskstats | 读/写完成数、扇区数、耗时毫秒、in-flight 请求数 |
| 网卡流量 | cat /proc/net/dev | 收发包与丢包计数 |
| 进程内存 | cat /proc/<pid>/status | VmRSS(物理内存)、VmSwap(换出量) |
| 进程 IO | cat /proc/<pid>/io | read_bytes、write_bytes、cancelled_write_bytes |
| 进程句柄 | ls /proc/<pid>/fd | wc -l | 句柄数量与指向的文件 |
| 进程上限 | cat /proc/<pid>/limits | Max open files 软硬限制 |
| 资源压力 | cat /proc/pressure/cpu | PSI:some/full 的等待时间占比 |
# 无 iostat 时,用 /proc/diskstats 算磁盘是否饱和(第 12 列为 in-flight IO 数)
awk '{print $3, "in_flight="$12+0, "read_ms="$7+0, "write_ms="$11+0}' /proc/diskstats | grep -E '^(sda|nvme0n1|vda)'
判读:in_flight 长期大于 1 说明设备有排队;把字段 11 与字段 7 相加再除以读写完成次数,就是设备平均每次 IO 的耗时(毫秒),数值明显高于平时的十几毫秒就是 IO 变慢。
三条组合命令
# 1. 一分钟看清全貌
uptime; free -h; df -h; df -i; ss -s; vmstat 1 5
# 2. 找出吃 CPU 的进程与线程
top -b -n 1 -o %CPU | head -20; top -Hp <pid> -b -n 1 -o %CPU | head -20
# 3. 找出吃磁盘的进程
iostat -x 1 3; pidstat -d 1 3; du -sh /var/log/* 2>/dev/null | sort -rh | head
使用注意
strace与perf都会给目标进程带来额外开销,生产上限制采集时间与频率,采完立即停。- 抓包(
tcpdump)在高流量机器上会丢包并占满磁盘,记得限制包数量与大小。 - 交互式工具(
top、iotop)尽量用-b批量模式输出到文件,便于留证与对比。 - 每个命令的输出都重定向一份到
/tmp,故障结束后可复盘,也防止终端回滚丢失。
预防与巡检
- 镜像里预装 sysstat、lsof、strace、perf,并开启
sar历史采集。 - 巡检脚本每天跑一次,把 load、内存、磁盘、inode、句柄数写入时序库。
- 把常用命令整理成运维手册贴在内网,凌晨三点不需要现搜参数。
小结:按 CPU、内存、磁盘、网络、进程、句柄、系统日志、JVM、DB 九个维度建立命令矩阵,默认用系统自带的 top/vmstat/df/ss/lsof,主动预装 sysstat 与 perf;工具缺失时用 /proc 里的 loadavg、stat、meminfo、diskstats、pid/io、fd 兜底,任何判断都以“看到一个具体数值”为前提。