Linux 运维高阶命令实战指南:五大场景排障 - 夜莺博客

Linux 运维高阶命令实战指南:五大场景排障

线上生产环境经常遇到负载飙高、日志刷屏、磁盘爆满、链路中断、进程僵死等故障,只会基础命令排障效率极低。本文按系统监控、日志分析、进程管理、磁盘运维、网络调试五大场景,整理运维高频高阶命令的核心用途、常用参数与实战用法,直接拿来就能用。

需要先建立一个观念:排障慢,往往不是因为命令不熟,而是因为没有分层。一台机器出问题,正确的顺序是先看整体负载(谁在消耗资源),再看具体维度(CPU、内存、磁盘 IO、网络四者中的哪一个到顶),最后才去看具体进程和日志。跳过前两步直接翻日志,是运维最常见的效率黑洞。下面每一节都按"先看什么、再看什么、怎么确认"的顺序组织,把命令放进判断链路里,而不是当成手册背诵。

一、系统性能监控与瓶颈定位

top:系统动态监控

top -d 2          # 刷新间隔 2 秒
top -p 1234       # 只监控指定 PID
top -u root       # 只看 root 用户进程
# 交互:P 按CPU排序  M 按内存排序  q 退出

top 顶部三行是判断依据:第一行 load average 的三个数值分别是 1、5、15 分钟的平均负载,与 CPU 核数对比判断是否过载(8 核机器负载 8 即满载);第二行看 %Cpu(s) 里的 us(用户态)、sy(内核态)、wa(IO 等待)、id(空闲),wa 高说明瓶颈在磁盘而不在 CPU;第三行看 available 而不是 free,free 只是一部分空闲内存,available 才代表新进程真正能拿到的内存。进入交互界面后,按 1 可以展开每个核心的利用率,多核机器上单核跑满而整体不高,往往是单线程应用或锁竞争导致。

htop:top 增强版

支持鼠标、树形父子进程、色彩区分;F2 自定义列、F4 关键字过滤、F9 发送信号。htop 的价值在于"按进程树看资源":一个 Java 主进程下面挂着几十个线程,用 htop 可以一眼看出是主进程在吃 CPU 还是某个线程在吃,而 ps 的输出需要人工拼接。排查内存泄漏时,F2 增加 RES、SWAP、TIME+ 列并按 TIME+ 排序,能快速找出长期占用 CPU 的常驻进程。

iostat:磁盘 IO 专项分析

iostat -d -x 1          # 每秒刷新扩展 IO 信息
iostat -d -x 1 sda      # 单独监控 sda
# %util 持续超 80% 基本判定 IO 瓶颈;await 过高表示磁盘处理缓慢

扩展模式下的关键列有三组。%util 表示设备忙的时间占比,持续超过 80% 说明队列已经排满;await 是平均每个 IO 的完成时间,含排队时间,机械盘超过 20 毫秒、SSD 超过 5 毫秒就值得怀疑;r/s 与 w/s 配合 avgrq-sz(平均请求大小)可以判断访问模式——大量小请求随机读写是数据库特征,大块顺序请求是备份或日志切割特征,两者的优化手段完全不同。

vmstat 与 sar:趋势与历史

vmstat 1 10             # 每秒采样一次,共 10 次
vmstat -s               # 汇总内存统计
sar -u -f /var/log/sa/sa14     # 回看 14 号的历史 CPU
sar -n DEV -f /var/log/sa/sa14 # 回看历史网卡流量

vmstat 的 r 列(运行队列)大于 CPU 核数说明 CPU 排队,b 列大于 0 说明有进程在不可中断睡眠,通常就是等磁盘。si/so 两列只要持续非 0,就意味着系统在真实地使用交换分区,性能会断崖式下降,这是内存不足最硬的证据。sa 文件是 sysstat 服务按天保留的历史数据,故障发生在凌晨、白天才被投诉时,sar 是唯一能"回到现场"的手段,建议把数据保留期调整到 30 天以上。

二、日志排查与文本处理

tail -n 100 app.log              # 查看末尾 100 行
tail -F app.log                  # 适配日志切割的实时跟踪
grep -C 5 "ERROR" app.log        # 错误前后 5 行上下文
grep -r "Exception" /var/log/    # 递归检索
awk '{print $1}' nginx.access.log                              # 提取客户端 IP
awk '$10>100' nginx.access.log                                 # 响应超 100ms 的请求
awk '{count[$1]++} END{for(ip in count) print ip, count[ip]}' nginx.access.log  # 每 IP 访问次数

tail -f 与 tail -F 的区别值得记住:日志被 logrotate 切割后,-f 跟随的是被重命名的旧文件句柄,屏幕上就再也不出新内容;-F 会按文件名重新打开,是生产环境唯一正确的实时跟踪方式。grep 的 -C(上下文)、-B(前)、-A(后)是定位错误的三件套,配合 --color=always 能把关键词高亮,肉眼扫描速度快很多。递归检索时加上 --include='*.log' 与 -E 扩展正则,能避免把二进制文件刷满终端。

awk 是日志统计的主力。上面三条是最高频的模板:按列取字段、按数值条件过滤、按字段聚合计数。实际工作中常见的变体还有:统计状态码分布 awk '{print $9}' access.log | sort | uniq -c | sort -rn、统计每分钟请求量 awk -F: '{print $2":"$3}' access.log | uniq -c、以及把慢请求整行导出到单独文件便于分析。日志时间戳格式不统一时,先用 sed 或 awk 把格式规整成 sort 能识别的形式,再做时间窗口统计。

sort access.log | uniq -c | sort -rn | head -20    # 出现次数最多的行
sed -n '/2026-09-14 10:00/,/2026-09-14 10:05/p' app.log   # 按时间窗口截取
journalctl -u nginx --since "30 min ago" --no-pager
journalctl -u nginx -p err -b                     # 本次启动以来的错误级别日志
journalctl --disk-usage; journalctl --vacuum-time=7d

systemd 管理服务的机器上,journalctl 往往比翻 /var/log 更直接:-u 指定服务、-p 限定级别、-b 限定本次启动、--since/--until 限定时间窗口。journal 默认按容量滚动,跑久了可能占几个 GB,用 --disk-usage 查看、--vacuum-time 或 --vacuum-size 收缩,是在磁盘告警时立竿见影的一步。

三、进程管理与异常恢复

ps -ef | grep java    # 查看 Java 相关进程
ps aux                # 按资源占用查看所有进程
pstree -p             # 进程树(带 PID),排查僵死子进程

ps aux 的输出里,STAT 列是判断进程状态的钥匙:R 运行、S 可中断睡眠(正常等待)、D 不可中断睡眠(通常在等磁盘 IO,无法被 kill)、Z 僵尸(已退出但父进程未回收)、T 被停止。大量 D 状态进程是磁盘或网络存储卡死的典型表现,此时重启服务往往无效,要先解决底层 IO。僵尸进程本身不占资源,但它说明父进程没有正确 wait,长期积累会耗尽 PID 表。

top -H -p 1234                      # 查看进程内线程
ps -L -p 1234 -o pid,tid,pcpu,stat  # 列出线程及各自 CPU
lsof -p 1234 | wc -l                # 该进程打开的文件数
lsof -p 1234 | grep -i log          # 它打开了哪些日志文件
lsof -i :8080                       # 谁占用了 8080 端口
ss -lntp                            # 监听端口与对应进程
strace -p 1234 -T -tt -e trace=network   # 跟踪系统调用(慎用,影响性能)
kill -15 1234                       # 优雅终止,让进程清理资源
kill -9 1234                        # 强制杀死,最后手段
pkill -f "java.*OrderService"       # 按命令行特征批量终止
renice -n 10 -p 1234                # 调整优先级而非杀进程

kill 的默认信号是 15(SIGTERM),它给进程机会执行关闭钩子、落盘、注销注册中心;-9(SIGKILL)是内核直接回收,进程没有任何收尾机会,可能导致数据不一致或分布式锁残留。所以正确的顺序永远是先 -15,等待若干秒确认没退出,再考虑 -9,并在事后检查是否有半写入状态需要人工修复。对于多实例无状态服务,先摘流量(下线注册中心、关闭健康检查)再重启,能把用户无感做到极致。renice 是常被忽略的替代方案:某个批处理占满 CPU 时,把它的优先级调低比直接杀掉它更安全。

四、磁盘存储排查

df -h                 # 分区使用率
df -i                 # inode 使用率(磁盘有空间却无法建文件的元凶)
du -sh /var/log/      # 目录总占用
du -h --max-depth=1 / | sort -nr | head -10   # 找出最大目录
find / -size +100M -type f                    # 大文件
find /var/log/ -mtime +7 -type f              # 7 天前日志
find /var/log/ -mtime +7 -type f -exec rm -rf {} \;

"磁盘满了"分两种:空间满和 inode 满。df -h 显示还有剩余空间却无法创建文件,用 df -i 看 inode 使用率即可确认;inode 耗尽通常是小文件海量堆积造成,比如缓存目录或 session 目录,处理办法是清理而不是扩容。另一种诡异情况是 df 显示已满但 du 统计的总和很小,这几乎一定是"已删除但仍被进程占用的文件"——进程持有句柄未释放,空间不会归还,用 lsof +L1 或 lsof | grep deleted 找到持有进程,重启它即可释放。

lsof +L1                            # 已被删除但仍被占用的文件
lsof | grep deleted | awk '{print $1,$2,$7,$9}'   # 定位持有点
ncdu /var                           # 交互式目录占用分析(需安装)
find /var/log -name "*.log" -mtime +7 -delete    # 删除 7 天前日志
journalctl --vacuum-size=500M       # 收缩 journal 占用
truncate -s 0 app.log               # 清空大文件而不删除(保留句柄)

用 > app.log 或 truncate -s 0 清空正在被写入的日志,比 rm 再让服务重建更安全:文件句柄保持不变,服务不需要重开文件,也不会出现"删了但空间没释放"。find -delete 与 -exec rm 的区别在于 -delete 更高效且内置了安全检查,但前提是 -name 或 -path 表达式足够精确。高危删除操作在国际惯例里有一条铁律:先执行不带删除动作的版本,确认输出列表符合预期,再在同一个命令上追加删除参数。

五、网络连通性与路由调试

ping -c 4 192.168.1.1     # 4 个包后停止,适配脚本
traceroute www.baidu.com  # 追踪路由节点,定位断点网关
mtr www.baidu.com         # ping+traceroute 合体,实时统计每跳丢包率与延迟,生产首选

mtr 是生产排障的首选,因为它把"路径"和"统计"合在了一起:-r 输出报告模式便于存档,-c 100 指定探测次数,-n 不做 DNS 反向解析(内网更快),--tcp -P 443 用 TCP 探测绕过 ICMP 限速。需要提醒的是,中间跳的丢包率不一定是真丢包,很多路由器对 TTL 超时的 ICMP 响应限速,真正要看的是最后一跳的丢包率和延迟抖动。有丢包且延迟阶梯式上升,说明瓶颈在某一跳;延迟正常但应用仍慢,问题往往不在网络上。

ss -antp | grep ESTAB                # 查看已建立连接及所属进程
ss -s                                # 连接数汇总(TIME_WAIT 暴涨时必看)
ss -ant state time-wait | wc -l      # TIME_WAIT 数量
ip -s link show eth0                 # 网卡收发计数与错误统计
ip route get 8.8.8.8                 # 查询实际选中的路由与源地址
ethtool -S eth0 | grep -i -E 'drop|err|discard'
tcpdump -i eth0 -nn port 80 -c 20    # 抓包确认报文是否真的到达
curl -w "@curl-format.txt" -o /dev/null -s https://example.com
telnet 10.0.0.1 3306                 # 快速验证端口可达性
nc -zv 10.0.0.1 3306                 # 脚本友好的端口探测

curl 的 -w 参数是定位"慢在哪一段"的利器,通过格式化模板可以分别输出 DNS 解析耗时、TCP 建连耗时、TLS 握手耗时、首字节时间与总耗时,从而区分是域名解析慢、网络握手慢,还是后端应用处理慢。ip route get 能同时给出选中的出口网卡和源地址,排查"同一台机器多网卡、回包走错网卡"这类不对称路由问题时比看整张路由表快得多。抓包前先确认计数器:ethtool -S 里的 rx_dropped 持续增长说明协议栈或缓冲区来不及处理,此时抓包看到的丢包是结果而不是原因。

六、典型故障场景速查

现象 第一判断命令 常见根因
整机负载高但 CPU 空闲率高 vmstat / iostat -x IO 等待或内存不足触发 swap
服务无响应,进程还在 top -H -p / jstack / pstack 线程死锁或线程池耗尽
磁盘有空间却无法写入 df -i / lsof +L1 inode 耗尽或删除文件未释放句柄
端口不通但服务在跑 ss -lntp / ip route get 监听地址绑定错误或防火墙 / 路由不对称
间歇性超时 mtr / tcpdump / ss -s 链路丢包、TIME_WAIT 占满或连接数上限
日志无输出 tail -F / journalctl -u 日志切割后句柄未重开,或写向被清空的文件

这张表的用法是反向的:先确定现象,再执行第一判断命令,把结论收敛到少数几种可能,然后才去查配置和代码。排障最大的浪费不是命令敲得慢,而是在错误的分支上深挖。

实战技巧总结

  1. 优先增强工具:htop 替代 top、mtr 替代 traceroute;
  2. 善用管道组合:筛选、排序、统计一站式完成;
  3. 摒弃死记参数:掌握核心场景用法即可;
  4. 高危操作(find 批量删除、kill)先查询确认,避免生产事故。
  5. 先分层再深入:整体负载 → 资源维度 → 进程 → 日志,不要跳步;
  6. 先取证再动手:把关键命令输出留存到工单或时间线,既便于复盘也便于交接;
  7. 把常用组合写成脚本或别名,故障时时间就是金钱。

相关阅读

Linux 性能排障工具大全见本站 Linux Performance Troubleshooting: Tools and Commands;网络故障定位思路见 Linux 网络故障排查:从网卡到路由的定位思路;需要更细的内核级追踪手段时看 bpftrace one-liners for production Linux debugging,涉及命名空间与虚拟网卡的隔离排障则参考 Linux network namespaces and veth pairs in practice。

原文链接:https://openeuler.csdn.net/6a101432662f9a54cb765a5a.html