1. 为什么我们需要一份Linux故障排查"作战地图"?
凌晨3点15分,刺耳的告警铃声划破深夜的宁静。服务器CPU负载飙升到800%,业务接口响应时间突破10秒,客户投诉电话开始涌入。作为值班工程师,你必须在最短时间内定位问题根源——是代码发布导致的线程泄漏?还是数据库连接池耗尽?亦或是遭遇了恶意攻击?
这就是Linux系统故障排查的典型场景:高压、紧急、信息爆炸。根据我十年运维经验,80%的初级工程师在这种时刻会陷入以下误区:
- 无头苍蝇式排查:在十几个终端窗口间来回切换,重复执行top/ps/netstat却看不出异常
- 经验主义陷阱:直接套用上次的处理方案,可能完全不对症
- 日志深渊:盲目grep几十GB的日志文件,耗时且低效
- 指标过载:同时盯着十几个监控图表,反而错过关键指标
真正的专业选手,都有一套结构化的"作战地图"。它不同于普通的命令手册,而是:
- 按故障现象快速定位可能原因
- 提供验证每个假设的最优命令组合
- 包含必须检查的"关键否决项"(比如磁盘inode用完不会在df中显示)
- 标注常见误判场景与交叉验证方法
下面这张经过上百次实战检验的作战地图,曾帮助我们在5分钟内定位过Kubernetes节点OOM、10秒发现过SSD寿命耗尽导致的IO卡顿。现在我将完整呈现其设计逻辑与使用心法。
2. 作战地图核心框架设计
2.1 故障现象分类树
所有Linux服务器故障最终会表现为以下四类核心症状:
| 症状大类 | 典型表现 | 首要检查点 |
|---|---|---|
| 资源耗尽 | CPU 100%、OOM、磁盘满 | top -Hp、dmesg、df -i |
| 服务异常 | 端口消失、进程退出、请求超时 | systemctl status、ss -tlnp |
| 性能劣化 | 延迟飙升、吞吐下降、卡顿 | sar -B、iostat -xmt 1 |
| 安全事件 | 异常连接、未知进程、文件篡改 | lsof -i、rpm -Va |
2.2 命令组合的战术原则
优秀的问题定位命令需要满足:
# 好的命令示例:显示进程CPU占用且保持刷新 top -b -n 1 -o %CPU | head -20 # 差的命令示例:仅显示静态进程列表 ps aux具体原则包括:
- 可自动化:支持非交互式运行(避免需要人工按键)
- 带时间戳:便于与监控系统时间轴对齐
- 关键字段突出:用awk/sort过滤噪音数据
- 低开销:避免在已负载的服务器雪上加霜
2.3 必须打印的基准信息
任何故障排查前,先运行以下命令建立系统快照:
# 系统基础信息 uptime; uname -a; free -h; df -hT; df -i # 内核关键日志 dmesg -T | tail -50 # 网络连接摘要 ss -s; ss -tlnp这些数据相当于"犯罪现场照片",后续分析时可能发现最初忽略的线索。
3. CPU异常全场景排查路径
3.1 瞬时CPU飙升定位法
当top显示CPU使用率突破90%时:
定位热点线程:
# 显示所有进程的CPU占用(-o %CPU按CPU排序) ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -20 # 显示某进程的所有线程CPU占用 top -Hp [PID] -b -n 1 | head -30分析线程类型:
# 将线程ID转为16进制(用于匹配jstack输出) printf "%x\n" [TID] # Java应用使用jstack检查线程栈 jstack [PID] | grep -A 20 [HEX_TID] # C++应用使用gdb获取堆栈 gdb -p [PID] -ex "thread apply all bt" --batch常见热点模式:
- GC线程:
GC task thread#0 (ParallelGC) - 锁竞争:
parking to wait for <0x00000000fe4a8d50> - 空转循环:
while(true)在用户代码中
- GC线程:
关键技巧:用
perf top -p [PID]实时观察热点函数,注意采样间隔不宜过短(建议3秒以上)
3.2 长期高负载分析策略
当sar -q显示load average持续高于CPU核数时:
检查运行队列:
vmstat 1 5 | awk '{print $1,$2,$(NF-2)}'- 如果
r列持续大于CPU核数,说明存在CPU竞争 b列大于0表示有进程被阻塞
- 如果
区分用户态/内核态:
mpstat -P ALL 1 3 | grep -v CPU%usr高:应用代码问题%sys高:内核/驱动问题
IO等待分析:
iostat -xmt 1 | grep -A 1 "%util"%util接近100%说明存储成瓶颈await大于10ms需要警惕
4. 内存问题精准打击方案
4.1 OOM连环案侦破
当dmesg出现Out of memory日志时:
确认触发条件:
grep -i oom /var/log/messages*- 注意
pages_free值,低于min_free_kbytes可能触发
- 注意
找出被杀进程:
journalctl -k --since "10 minutes ago" | grep -i kill内存分配分析:
# 显示各进程内存占用(RES列) ps -eo pid,ppid,cmd,%cpu,%mem,rss --sort=-rss | head -20 # 检查内存泄漏工具 valgrind --tool=memcheck --leak-check=full ./program
4.2 隐藏的内存杀手
以下情况不会直接体现在free输出中:
Slab内存泄漏:
slabtop -o | head -20- 观察
dentry、inode_cache是否异常增长
- 观察
透明大页问题:
cat /sys/kernel/mm/transparent_hugepage/enabled- 建议设为
madvise而非always
- 建议设为
内存碎片化:
cat /proc/buddyinfo- 小阶(0-3)区块不足表明碎片严重
5. 磁盘IO问题刑侦技术
5.1 响应延迟飙升分析
当iostat -x显示await>50ms时:
区分读写类型:
iostat -xm 1 | grep -A 1 "Device"r_await高:可能是存储硬件问题w_await高:可能是文件系统或RAID卡缓存问题
文件系统检查:
# 查看挂载参数 mount | grep -E "^/dev" # 检查是否有noatime,nobarrier等优化参数缺失LVM性能诊断:
lvs -o +devices; pvs; vgs dmsetup status
5.2 空间不足的陷阱
当df -h显示使用率<90%但应用报"no space"时:
inode耗尽检查:
df -i- 特别是小文件多的分区
配额限制验证:
repquota -a | grep -v "none"文件删除未释放:
lsof +L1 | grep deleted- 找到被删除但仍被进程占用的文件
6. 网络问题侦探手册
6.1 连接异常排查
当应用出现Connection refused或Timeout时:
端口存活验证:
nc -zv [IP] [PORT] telnet [IP] [PORT]防火墙检查:
iptables -L -n -v nft list ruleset连接跟踪表:
conntrack -L | grep [IP] sysctl net.netfilter.nf_conntrack_max
6.2 性能问题定位
当网络延迟高或吞吐低时:
基础链路测试:
ping -c 10 [IP] mtr --report [IP]带宽质量测量:
iperf3 -c [SERVER_IP] -t 20协议栈调优:
sysctl -a | grep net.ipv4.tcp- 关键参数:
tcp_tw_reuse、tcp_slow_start_after_idle
- 关键参数:
7. 作战地图实战演练
7.1 案例:数据库响应变慢
现象:
- MySQL查询从平均10ms飙升到2s
- CPU使用率60%,iowait 25%
排查过程:
- 确认不是CPU瓶颈(
%sys仅15%) - 发现
iostat中await高达200ms - 检查
dmesg发现SSD有[sdb] tag#0 FAILED错误 - 使用
smartctl -a /dev/sdb确认SSD出现坏块 - 更换磁盘后恢复正常
7.2 案例:API间歇性超时
现象:
- 每2-3小时出现持续1分钟的接口超时
- 期间TCP重传增多
排查过程:
- 在故障时段
ss -ti发现大量retrans netstat -s显示TCPTimeouts增长- 检查
sysctl net.ipv4.tcp_keepalive_time为7200(太大) - 调整为600后问题消失
8. 高级武器库扩充
8.1 BPF工具链
# 跟踪慢IO请求 bpftrace -e 'tracepoint:block:block_rq_complete { if (args->nr_sector > 16 && args->error == 0) { @[kstack] = count(); } }'8.2 内核追踪点
# 统计进程调度延迟 perf stat -e 'sched:sched_stat_wait' -a sleep 108.3 线上诊断神器
gdb附加到生产进程:
gdb -p [PID] -ex "thread apply all bt" --batch无需安装的strace:
nsenter -t [PID] -n strace -p [TID]
这套作战地图的真正价值不在于命令本身,而在于建立系统化的排查思维。建议打印出来贴在工位,遇到报警时按图索骥,至少能节省50%的故障恢复时间。