一行破局:只掌握这 15 个 Linux 核心命令,90% 的生产故障都能一行解决
真正让工程师拉开差距的,不是会不会背命令,而是告警响起之后,能不能在 3 分钟内把“症状”收敛成“证据”,再把“证据”收敛成“根因”。
线上故障最怕两件事:第一,大家都觉得自己知道问题在哪;第二,没有人先把现场钉住。Linux 命令行的价值,就在于它能帮你用最短路径拿到第一手证据。监控告诉你“系统出事了”,而 /proc、socket、线程栈、文件描述符和系统调用,才真正告诉你“到底为什么出事”。
很多文章喜欢把 Linux 命令写成速查表,但生产环境并不缺速查表,缺的是一条稳定的排障路径。你需要知道:
- • 内存涨时,先判断 Java 堆、堆外内存还是页缓存。
- • 网络超时时,先看连接状态、重传,还是应用没有及时
close。 - • 容器里没有工具时,如何穿透 namespace 把宿主机的工具链借进来。
这篇文章不准备做“命令大全”,而是围绕生产故障里最常见的 15 个核心命令,给你一套可以直接上手的排障框架。它们分别是:
top、ps、pidstat、jstack、pmap、cat /proc/*/smaps、vmstat、iotop、lsof、ss、tcpdump、strace、journalctl、nsenter、sar
其中有些不是独立二进制意义上的“单个命令”,比如 smaps 依赖 /proc 文件系统,但它们在生产一线的价值完全够得上“核心命令”这四个字。
一、为什么“一行命令”才是生产故障的分水岭?
线上故障的本质不是“信息不够多”,而是“现场太嘈杂”。Prometheus、Grafana、APM、链路追踪、日志平台会同时抛出大量症状:
这些都是真的,但它们未必是根因。真正有经验的工程师不会一上来就改配置、扩容或者重启,而是先回答三个问题:
一行命令的价值,正是把排障从“感觉判断”变成“证据驱动”。
更具体一点,生产排障几乎都可以落到下面这条路径上:
告警症状 -> 锁定资源维度 -> 锁定进程/线程/连接/文件 -> 读取内核暴露证据 -> 关联应用代码或配置 -> 修复 -> 验证 -> 防复发
所以命令不是炫技,而是工程化排障的最短闭环。
二、先记住这条总路线:不要一上来就“猜”
如果你只记一条规则,我建议你记这一条:
先用廉价命令缩小范围,再用重型命令拿最终证据。
所谓廉价命令,就是开销低、信息广、适合快速扫描的命令,比如:
所谓重型命令,就是 attach、抓包、深入进程内部,可能影响性能或需要更高权限的命令,比如:
这背后有两个工程原则。
第一,不要在根因未明时扩大故障面。比如一个高 QPS Java 进程已经抖动严重,此时贸然长时间 strace -f,有可能进一步放大延迟。
第二,排障不是收集越多信息越好,而是越早得到“能做决策的证据”越好。很多故障只要一条线程栈、一组 socket 状态分布、一次 IO 文件列表,就足以结束争论。
三、CPU 飙升:从 Pod 扩容无效,到锁定哪一段代码在空转
3.1 场景:容器内 Java 服务 CPU 100%,HPA 一直扩容,但延迟并没有下降
这类问题最典型的误判是:看到 CPU 高,就先扩容。
但如果根因是代码热点、自旋锁竞争、GC 抖动、线程池错误配置,扩容通常只会把问题复制到更多副本上。正确动作是先判断:
3.2 第一条命令:先看整机是否真的是 CPU 瓶颈
vmstat 1 5
重点看四组指标:
- •
r:可运行队列长度,持续大于 CPU 核数,说明抢占严重。 - •
us:用户态 CPU 占比,通常对应业务代码、JIT、GC 用户态计算。 - •
sy:内核态 CPU 占比,偏高时要怀疑系统调用、网络栈、锁竞争。 - •
wa:IO wait,高则可能是假性“CPU 高”,实则在等磁盘。
为什么先看 vmstat 而不是直接看某个进程?因为你要先确认,问题是局部热点,还是宿主机资源竞争。很多 K8s 节点问题,根因不是你的 Pod,而是同机 noisy neighbor。
3.3 第二条命令:锁定最耗 CPU 的进程
top -b -n1 -o %CPU | head -20
如果你知道服务名,也可以更直接:
ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -15
这一步不是为了“看到 CPU 高”这种废话,而是为了回答两个实际问题:
- • 热点是在 Java、Go、Nginx,还是 sidecar、日志采集、JVM 附属进程。
3.4 第三条命令:锁定线程,而不是只停留在进程层
top -H -b -n1 -p 6 | awk 'NR>7 {print $1,$9,$12}' | sort -k2 -rn | head -5
如果想更稳定地连续观察线程波动,用:
pidstat -t -p 6 1 5
top -H 适合快照式定位,pidstat -t 适合观察线程 CPU 是否持续集中在同一批线程上。持续集中,往往意味着代码热点;频繁切换,则要怀疑抢锁、线程池抖动或请求风暴。
3.5 第四条命令:把线程 ID 对上 Java 栈
jstack 6 | grep -A 30 "0x$(printf '%x\n' 243)"
其中 243 是你从 top -H 或 pidstat -t 拿到的线程 ID。
这条命令的价值,不在于“打印线程栈”,而在于完成了从内核调度对象到应用代码位置的映射:
这样你就能把“CPU 高”落到诸如以下具体根因:
- • Full GC 或 Remark 线程持续占用 CPU
3.6 一行组合:真正能在现场救命的版本
pid=$(pgrep -f 'java.*user-center'); tid=$(top -H -b -n1 -p "$pid" | awk 'NR>7{print $1,$9}' | sort -k2 -rn | head -1 | awk '{print $1}'); printf 'pid=%s tid=%s hex=%x\n' "$pid" "$tid" "$tid"; jstack "$pid" | grep -A 30 "0x$(printf '%x\n' "$tid")"
3.7 这类问题常见的真实根因
- • SQL 变慢,线程大量阻塞前后伴随少数线程在连接池争抢和超时重试中耗尽 CPU。
- • 线程池队列太小,拒绝策略触发后业务层疯狂降级重试。
- •
synchronized 热点锁导致竞争线程不断唤醒和挂起。 - • 应用误把批处理逻辑跑在请求线程里,导致单次请求计算量异常放大。
3.8 修复后如何验证
不要只看“CPU 降下来了”,要一起验证:
很多事故里,CPU 高只是二次症状,真正根因在下游资源阻塞。
四、内存上涨:不要只盯着堆,堆外内存、页缓存和映射文件同样会杀死进程
4.1 场景:服务内存持续上涨,最终被 OOMKilled,但堆 dump 看起来不大
这是线上极常见的坑。
很多人看到 Java 进程内存高,第一反应就是“堆泄漏”。可在容器环境里,真正把进程送走的,可能是:
4.2 第一条命令:先看系统是不是整体在换页或回收压力中
vmstat 1 5
重点看:
- •
si / so:swap in / swap out,不为 0 时说明已经开始换页
如果宿主机本身在抖,说明问题不一定只在单个进程。
4.3 第二条命令:用 pmap 看 RSS 到底花在哪
pmap -x 6666 | sort -k3 -nr | head -10
这里最有价值的是按 RSS 排序后的内存映射段。你通常会看到:
如果匿名段异常大,而堆又没有同步变大,优先怀疑堆外内存或本机内存泄漏。
4.4 第三条命令:深入到 smaps 看分段细节
cat /proc/6666/smaps | grep -A 20 "7f2a00000000"
smaps 比 pmap 更细,能看到:
它真正解决的是“这段内存到底是共享页、私有脏页,还是已经换出”。这对判断是不是页缓存、是不是文件映射异常、是不是本机分配失控非常关键。
4.5 一行组合:快速抓出堆外占用 TOP
pid=$(pgrep -f 'java.*user-center'); pmap -x "$pid" | awk 'NR>2 {print $3,$4,$NF}' | sort -nr | head -10
4.6 这类问题为什么经常误判
因为语言运行时给你的监控视角,往往只覆盖“托管内存”,但 Linux 杀进程时看的是 cgroup 或宿主机视角下的实际占用。也就是说:
中间那 3G,往往就在 native memory、线程栈和文件映射里。
4.7 工程上的防复发手段
- • Java 服务开启
-XX:NativeMemoryTracking=summary 或 detail - • 对 Netty、Arrow、RocksDB 等堆外内存敏感组件设上限
- • 监控进程 RSS、容器 working set、page cache,而不是只看堆使用率
- • 在大文件或索引加载场景中关注
mmap 数量和页缓存回收行为
五、磁盘 IO 风暴:真正要找的不是“磁盘忙”,而是谁在写、写到哪、为什么必须同步写
5.1 场景:数据库从库延迟飙升,应用日志也开始超时,节点 iowait 很高
这时最容易出现两种错误动作:
但很多时候,磁盘风暴根因不是设备坏,而是某个进程的写入模式突然变了,比如:
- • checkpoint 或 compaction 突然触发
5.2 第一条命令:先确认是不是 IO 等待导致系统变慢
vmstat 1 5
如果 wa 明显升高,同时 us 并不高,说明 CPU 并没有真忙,线程大概率是在等 IO。
5.3 第二条命令:锁定最重的 IO 进程
iotop -b -n1 -o -P | awk 'NR>3 {print $1,$4,$6,$12}' | head -10
这一步能回答:
- • 是 MySQL、Java、日志采集器还是备份进程在写
5.4 第三条命令:用 lsof 把进程和文件关联起来
lsof -p 12345 | awk '/REG/ {print $9}' | sort | uniq | head -30
这是磁盘排障的分水岭。因为从“进程很忙”到“它到底在操作哪个文件”,中间往往就隔着一个 lsof。
你会很快看到是:
5.5 一行组合:先抓进程,再列文件
pid=$(iotop -b -n1 -o -P | awk 'NR==4{print $1}'); echo "PID=$pid"; lsof -p "$pid" | awk '/REG/ {print $9}' | sort -u | head -30
5.6 为什么这条证据链很重要
因为 IO 问题非常容易跨层误导:
- • 数据库复制延迟,看起来像数据库问题,实际是宿主机某个归档任务把磁盘写爆
- • 接口超时,看起来像应用代码慢,实际是日志同步刷盘拖垮请求线程
- • Kafka 消费积压,看起来像消费逻辑异常,实际是 broker 所在盘延迟抖动
5.7 如果还想确认是不是同步刷盘或文件锁问题
strace -f -e trace=fsync,fdatasync,open,openat -p 12345
这一步是重型证据。它能直接告诉你进程是不是在高频 fsync,或者是否不断打开某个文件。
六、网络超时:ping 正常没有意义,连接状态和重传才是真相
6.1 场景:微服务调用大量超时,应用日志写满了 Read timed out,但 ping 正常
生产里最常见的网络误判,就是用 ping 正常来排除网络问题。
但应用层超时常见根因很多根本不是 ICMP 能解释的:
- • NAT、负载均衡或 sidecar 连接跟踪异常
6.2 第一条命令:看 socket 状态分布
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
如果你看到下面这些状态异常增多,含义完全不同:
- •
TIME-WAIT 多:短连接风暴或连接复用策略不好 - •
CLOSE-WAIT 多:应用层没有及时关闭连接
6.3 第二条命令:只看可疑状态
ss -tan state close-wait
或:
ss -tan state syn-sent
你不需要一上来抓包。大多数情况下,ss 已经足够把问题缩小到连接生命周期的某个阶段。
6.4 第三条命令:看重传是否持续增长
sar -n TCP,ETCP 1 5
如果系统有 sysstat,这比老式 netstat -s 更适合持续观察。重点看:
当 retrans/s 明显抬升时,要继续怀疑链路丢包、队列拥塞、对端过载或网卡/驱动问题。
6.5 第四条命令:只抓你关心的握手与重置
tcpdump -i eth0 -nn 'tcp port 8080 and (tcp[tcpflags] & (tcp-syn|tcp-rst) != 0)' -c 100
为什么不是一上来全量抓包?因为生产流量大时,全量抓包既影响性能,也不利于快速分析。抓 SYN、RST、少量样本,通常更快回答问题:
6.6 一个真实得不能再真实的案例
很多 Java 服务的 CLOSE_WAIT 问题,并不是操作系统 bug,而是代码没写好:
这时 ss 给你的已经不是“网络问题”线索,而是应用资源释放问题线索。
七、启动卡死、无日志、无响应:strace 是最锋利的最后一刀
7.1 场景:服务启动后不报错,也不监听端口,日志几乎没有输出
这种问题最折磨人,因为看起来“什么都没发生”。
但对操作系统来说,只要进程还活着,它就一定在做某些系统调用。于是 strace 的价值就出来了。
7.2 一行命令:直接看它卡在什么系统调用
strace -f -e trace=open,openat,connect,read,write,flock -p $(pgrep -f myapp) 2>&1 | head -40
你常见到的根因会非常具体:
- •
open(...)= -1 ENOENT:配置文件或动态库缺失 - •
connect(...)= -1 ETIMEDOUT:启动依赖外部注册中心或数据库超时 - •
flock(...) 长时间不返回:文件锁竞争 - •
read(...) 一直阻塞:等管道、等 FIFO、等设备
7.3 为什么 strace 这么有效
因为它直接绕过了应用日志的主观性。
日志可能没打出来,日志级别可能不够,代码可能压根没走到 catch;但系统调用是进程和内核的真实边界。你看到的不是“开发者以为程序在干什么”,而是“程序真的在跟操作系统交互什么”。
7.4 什么时候不要长时间用 strace
strace 适合做精确定位,不适合当长期监控工具。
八、容器时代的排障分水岭:容器里没有工具,不等于你看不到现场
8.1 场景:线上容器是 distroless,没有 shell、没有 top、没有 lsof
这是 K8s 生产环境的常态,而不是例外。镜像越精简,运行越安全,排障就越依赖宿主机工具链。
8.2 关键命令:先找到容器对应的宿主机 PID
docker inspect --format '{{.State.Pid}}' <container_id>
如果是 containerd/CRI:
crictl inspect <container_id> | jq .info.pid
8.3 一步穿透 namespace
nsenter -t <pid> -a -- ss -tanp
也可以:
nsenter -t <pid> -m -p -- jstack 1
或者:
nsenter -t <pid> -n -- tcpdump -i any -nn 'tcp port 8080'
8.4 为什么 nsenter 是容器排障必修课
因为容器隔离靠的是 namespace,而不是“另一台机器”。目标进程的网络栈、挂载点、PID 视图,本质上都还是宿主机内核在管理。nsenter 做的事,就是调用 setns() 进入目标命名空间,把宿主机工具借进去。
这意味着:
- • 你可以把排障能力做成节点级标准操作,而不是容器内手工操作
8.5 生产建议
- • 做一套标准化
diag.sh 或 node-debug 脚本 - • 给 SRE 和核心研发准备只读排障权限,而不是 root 漫游
- • 把进入容器 namespace 的流程纳入值班手册
九、别忽略系统日志:很多“玄学问题”其实早就写在 journalctl 里
9.1 场景:服务偶发失败,重启后恢复,但你总觉得不是应用自身问题
有一类故障不是进程内部逻辑,而是系统外围在出问题:
这时应用日志常常是不完整的,因为进程来不及说话就被外部环境处理掉了。
9.2 一行命令:看最近系统级异常
journalctl --since "10 min ago" -p warning
如果是具体服务:
journalctl -u myapp --since "10 min ago"
你能快速拿到的信息包括:
9.3 为什么很多人会漏掉这一步
因为大家默认觉得“故障一定是业务代码引起的”。但在复杂生产环境里,业务代码只是最后承压的一层。真正的根因可能在宿主机、内核、文件系统或运行时。
十、历史视角同样重要:sar 解决的是“现在看不见刚才发生了什么”
10.1 场景:你登录到机器时,故障已经过去一半了
很多线上问题最尴尬的点在于:
如果你只看当前快照,很可能会得出“现场看起来还好”的错误结论。
10.2 一行命令:回看刚才的 CPU、网络、磁盘波动
sar -u -r -n DEV 1 5
如果系统启用了历史采样,还可以回看采样文件。sar 的价值不在于比实时命令更酷,而在于它能回答:
这对区分“突发流量”“慢性泄漏”“定时任务打点”“批处理冲击”非常有帮助。
十一、把 15 个命令串成一条真正可执行的排障链
到这里你会发现,这 15 个命令并不是孤立存在的。它们在生产里更像一套组合拳。
11.1 CPU 型故障
推荐路径:
vmstat -> top / ps -> pidstat -> jstack
适合解决:
11.2 内存型故障
推荐路径:
vmstat -> pmap -> smaps -> journalctl
适合解决:
11.3 IO 型故障
推荐路径:
vmstat -> iotop -> lsof -> strace
适合解决:
11.4 网络型故障
推荐路径:
ss -> sar -> tcpdump -> journalctl
适合解决:
11.5 容器型故障
推荐路径:
docker inspect / crictl inspect -> nsenter -> 复用上述所有命令
适合解决:
十二、一行命令图谱:15 个核心命令到底分别看什么
| | | |
|---|
top | | | |
ps | | | |
pidstat | | | |
jstack | | | |
pmap | | | |
smaps | | | |
vmstat | | | |
iotop | | | |
lsof | | | |
ss | | | |
tcpdump | | | |
strace | | | |
journalctl | | | |
nsenter | | | |
sar | | | |
十三、真正的生产经验,不是背命令,而是知道哪些命令不能乱用
命令会不会用,只是初级差异;知道什么时候不用,才是生产经验。
13.1 三条很重要的边界
第一,重型命令不要在未知高峰上盲打。
比如:
- • 不要对已经抖动严重的核心进程长时间
strace -f - • 不要在大流量节点上无过滤地
tcpdump -i any
第二,不要脱离业务上下文解释系统证据。
例如看到 TIME_WAIT 多,不一定是 bug,也可能是短连接设计本来如此;看到磁盘忙,也不一定是数据库慢,可能是日志系统或备份任务。
第三,不要把“当前快照”误当成“整个故障过程”。
很多故障在你登录时已经发生了演化:
所以历史指标和系统日志一定要一起看。
十四、从“会排障”到“少排障”:把一行命令沉淀成工程能力
如果团队排障仍然依赖个人英雄主义,那说明系统还不够工程化。
更成熟的做法,是把这些命令沉淀成标准能力。
14.1 建一套节点级诊断脚本
例如把以下能力固化进 diag.sh:
这样值班同学不用临场拼命回忆参数。
14.2 给监控加“命令语义映射”
比如:
- • 看到
CLOSE_WAIT 激增,就联想到 ss - • 看到容器内存高但堆正常,就联想到
pmap/smaps - • 看到
iowait 高,就联想到 iotop + lsof
成熟团队的值班手册,应该能把告警直接映射到下一条命令,而不是映射到“请拉群讨论”。
14.3 把防复发闭环补齐
命令只能帮你找到根因,真正减少事故频率的,是后面的治理动作:
- • 连接泄漏补充 finally 释放和连接池监控
十五、结语:命令是术,证据链才是道
只会背命令,最多算熟练工;能够把命令、内核视角、运行时机制和业务现场串成一条证据链,才算真正具备生产排障能力。
这 15 个 Linux 核心命令之所以重要,不是因为它们覆盖了所有故障,而是因为它们足够稳定、足够底层、足够接近真实现场。无论你跑的是 Java、Go、Node.js,还是容器、虚拟机、裸机,最终都要落回 CPU、内存、IO、网络、进程和系统日志这些基本面上。
所以,别把它们当成“面试题”去背。
把它们练成下面这套条件反射,才真正有意义:
- • 看到 CPU 高,先判断整机还是进程,再落到线程和栈
- • 看到超时,先看 socket 状态和重传,而不是先怪网络
- • 看到容器里没工具,第一反应是
nsenter,而不是手忙脚乱地重建镜像
真正的一行破局,不是“只敲一行命令就解决问题”,而是你知道哪一行最值得先敲,敲完之后下一步该去哪,什么时候已经拿到足够证据,什么时候该立刻止损、修复、回滚。
这,才是生产故障里最值钱的能力。
建议你在测试环境刻意练习一遍这套路径:主动制造 CPU 热点、连接泄漏、磁盘刷盘抖动和容器内无工具场景,然后强迫自己只用命令行完成定位。练过和没练过,值班时的心理稳定性完全是两个层级。