Linux 排错手册
Linux 排错手册
[!abstract] 定位 SRE 面试必考科目。覆盖 CPU、内存、磁盘 IO、进程、文件描述符五大维度的排错命令、标准排查链路和面试话术。
一、CPU 飙高排查
标准排查链路
graph TB
A[CPU 飙高告警] --> B[top 看整体]
B --> C{us 高还是 sy 高?}
C -->|us 用户态高| D[应用层问题]
C -->|sy 内核态高| E[系统调用/IO 问题]
C -->|ni 高| F[其他高优先级进程抢占]
C -->|wa 高| G[IO 等待 → 看磁盘]
D --> D1[top -Hp PID 找线程]
D1 --> D2[线程 TID 转十六进制]
D2 --> D3[jstack PID 查线程栈]
E --> E1[perf top / strace -p PID]
E1 --> E2[看系统调用分布]
逐层命令
# 1. 宏观:看整体 CPU 分布
top
# us = 用户态(业务代码、JVM GC)
# sy = 内核态(系统调用、上下文切换)
# wa = IO 等待(磁盘瓶颈)
# id = 空闲
# 2. 找进程
top -bn1 | head -20
# 或更精确
ps aux --sort=-%cpu | head -10
# 3. 找线程(关键!)
top -Hp <PID>
# 记录占用最高的线程 TID
# 4. 转十六进制
printf '%x\n' <TID>
# 例如:printf '%x\n' 12345 → 3039
# 5. 查 Java 线程栈
jstack <PID> | grep -A 30 '0x3039'
# 能直接看到哪个方法在狂跑 CPU
# 6. 非 Java 进程?用 strace/perf
strace -p <PID> -c # 统计系统调用耗时分布
perf top -p <PID> # 实时看 CPU 热点函数
perf record -p <PID> -g # 采样,生成火焰图
常见根因速查
| 症状 | 排查命令 | 常见原因 |
|---|---|---|
us 高,单线程 | top -Hp → jstack | 死循环、正则回溯、无限递归 |
us 高,多线程均匀 | jstack 多线程都是同一个方法 | GC 频繁、业务计算密集 |
sy 高 | strace -c 看系统调用 | 大量上下文切换、频繁 futex、短连接风暴 |
wa 高 (>10%) | iostat -x 1 看磁盘 | 磁盘 IO 瓶颈 |
二、内存排查
标准排查链路
# 1. 整体看
free -h
# total used free shared buff/cache available
# 关注 available(实际可用),不是 free
# 2. 进程级
top -o %MEM # 或 ps aux --sort=-%rss
pmap -x <PID> | tail -1 # 进程内存明细
cat /proc/<PID>/status | grep Vm # VmRSS, VmSize, VmData
面试高频:free vs available
[!important] 面试金句 「
free是完全没有被使用的内存。available是包括可以回收的缓存和 buffer 以后的实际可用内存。Linux 会尽可能用空闲内存做文件缓存(buffer/cache),这是正常行为,不是内存泄漏。只有当available持续下降且不回升,才是真正的内存压力。」
Java 进程内存排查
# 堆内存
jmap -heap <PID>
# 堆外内存(容易被忽略的内存泄漏来源)
# 堆外 = 总 RSS - 堆
# 如果堆外持续增长 → DirectByteBuffer 泄漏、JNI 泄漏、thread stack 过多
jcmd <PID> VM.native_memory summary
# OOM 时自动 dump(JVM 参数)
# -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump/
常见根因速查
| 症状 | 排查 | 原因 |
|---|---|---|
| OOM Kill | dmesg | grep -i oom 看被杀的进程 | 内存超限,K8s limits 太低或真的泄漏 |
available 持续下降 | 长期监控趋势 | 真内存泄漏或缓存膨胀 |
| Swap 使用 > 0 | vmstat 1 看 si/so 列 | 内存不足在换页,严重性能问题 |
| OOMKilled (K8s) | kubectl describe pod → Last State 的 Exit Code 137 | 137 = SIGKILL = OOM |
三、磁盘 IO 排查
# 1. 整体 IO 分布
iostat -x 1
# 关注:
# %util → 磁盘繁忙度,接近 100% 表示瓶颈
# await → IO 平均等待时间 (ms)
# r/s, w/s → 读写 IOPS
# rkB/s, wkB/s → 读写吞吐量
# 2. 找元凶进程
iotop -o # 只显示有 IO 的进程
pidstat -d 1 # 按进程统计 IO
# 3. 深挖:这个进程在读什么文件?
lsof -p <PID> | grep REG # 打开的文件
strace -p <PID> -e trace=read,write 2>&1 | head -50
常见根因速查
| 症状 | 排查 | 原因 |
|---|---|---|
%util 100%, r/s 和 w/s 都不高 | iostat 看 avgrq-sz | 顺序大 IO(如日志切割、备份),带宽打满了 |
await > 50ms | iostat + iotop | 磁盘性能不足或坏道 |
%util 高但 CPU wa 不高 | 可能是 SSD | SSD 的等待时间短,CPU 不阻塞 |
| 某个进程 IO 大 | lsof 看是哪个文件 | 应用日志没轮转、数据库 binlog 刷盘 |
四、进程与文件描述符
# 查进程(不只 ps aux)
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head
pstree -p <PID> # 进程树
# 查文件描述符泄漏
lsof -p <PID> | wc -l # 当前进程打开的 fd 数
lsof -p <PID> | awk '{print $9}' | sort | uniq -c | sort -rn | head # 最多的是什么类型
ls -la /proc/<PID>/fd | wc -l # 同上
# 系统级 fd 限制
ulimit -n # 当前 shell
cat /proc/<PID>/limits | grep 'open files' # 进程级
# 查僵尸进程
ps aux | grep 'Z'
# 如果有 zombie → 父进程没 wait() 回收子进程
Fd 泄漏的典型场景
- HTTP 连接池没关 →
ESTABLISHEDsocket 堆积 - 文件没 close → 打开的文件句柄持续增长
- 管道/FIFO 没释放 → Java NIO 的
Pipe未关闭
五、性能分析进阶工具
# 火焰图(Brendan Gregg 的 perf-tools)
perf record -F 99 -p <PID> -g -- sleep 30
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > flame.svg
# eBPF 工具(bcc-tools)
execsnoop # 追踪 exec 调用(谁在执行命令)
opensnoop # 追踪 open 调用(谁在打开文件)
tcptop # 实时 TCP 流量 Top
biolatency # 磁盘 IO 延迟分布直方图
# 快速看系统瓶颈
vmstat 1 # CPU、内存、IO 全景 1s 刷新
sar -n DEV 1 # 网络流量历史
六、面试话术模板
[!quote] 被问「你常用的 Linux 排查命令」
「我一般按五个维度来排查:CPU、内存、磁盘 IO、网络、文件描述符。」
「CPU 的话,先 top 看整体,如果是用户态高就用 top -Hp 找线程,Java 用 jstack 定位到代码行,非 Java 用 perf 或 strace。如果是内核态高说明系统调用或上下文切换太频繁。」
「内存的话注意 free 的 available 而不是 free,buffer/cache 是正常行为。进程级用 pmap 和 /proc/PID/status,Java 额外关注堆外内存。」
「磁盘 IO 看 iostat -x,%util 接近 100% 就是瓶颈,iotop 找元凶进程,lsof 确认在写什么文件。」
「文件描述符 lsof -p PID | wc -l,接近 ulimit -n 就要排查泄漏。」
#sre #linux #面试