资讯动态

Linux运维故障排查的100条高可用命令实战指南

发布时间:2026/10/23 7:02:02 来源:尧图企业网站定制
1. 这不是命令清单而是一份“故障现场还原手记”你有没有过这样的经历凌晨两点监控告警疯狂闪烁某个服务响应时间飙升到12秒日志里全是Connection refused你连上服务器第一反应是敲ps aux | grep nginx结果发现进程根本没在跑——但systemctl status nginx却显示“active (running”你再查端口netstat -tuln | grep :80空空如也最后翻配置才发现nginx.conf里监听端口被误写成listen 8080;而上游负载均衡器还在死命往80端口发流量……整个过程耗时47分钟其中32分钟花在了“确认到底该查什么”。这100条Linux命令不是为考试准备的默写题也不是给新手看的“hello world”式演示。它们是我过去十年在某跨平台系统运维团队、某高校高性能计算实验室、某云原生中间件支持组里从真实故障现场、性能压测瓶颈、上线回滚瞬间、安全审计突击检查中一条一条抠出来的“生存反射”。比如lsof -i :8080和ss -tuln | grep :8080看起来功能重叠但前者在容器环境常因PID命名空间隔离返回空后者却能穿透cgroup层级直接看到宿主机网络栈状态再比如du -sh * | sort -hr | head -5看似简单可一旦目录下存在百万级小文件*通配符会触发shell参数列表溢出必须改用find . -maxdepth 1 -type d -exec du -sh {} | sort -hr | head -5才能稳住。关键词里虽然没填但整套逻辑锚定在三个不可妥协的维度上精准性命令输出必须直指根因不靠猜、抗干扰性在高负载、磁盘满、OOM Killer刚杀过进程的残局里依然可用、上下文自洽性单条命令的结果必须能自然衔接到下一条形成排查链路。所以你看不到cal或yes这种“有趣但无用”的命令也找不到kill -9 $(pgrep java)这种危险操作——它会被拆解成pgrep -f spring-boot先确认进程意图再用jstack $(pgrep -f spring-boot) /tmp/jstack.out 21捕获线程快照最后才执行kill -15并观察journalctl -u myapp --since 2 minutes ago的日志收尾动作。我带过的A同学第一次独立处理线上问题就是靠这套命令组合拳定位到某数据库连接池泄漏先用watch -n 1 ss -s发现TCP: time wait连接数每秒涨3个再用ss -tulnp | grep :3306 | wc -l确认是MySQL端口异常接着lsof -i :3306 | awk {print $2} | sort | uniq -c | sort -nr | head -3揪出三个高频PID最后对每个PID执行cat /proc/{pid}/cmdline | tr \0 \n反向验证启动参数——全程没重启服务也没动任何配置22分钟完成根因锁定。这不是魔法是把每条命令当成手术刀知道切哪层组织、避开哪些血管、留多少安全余量。2. 命令选型背后的“三重过滤”逻辑为什么是这100条而不是120条或80条为什么htop入选而top仅作备注为什么ripgreprg替代了grep -r答案藏在我们团队内部推行的“三重过滤”机制里第一重过滤是故障场景覆盖率第二重是资源消耗阈值第三重是人机交互效率。这三道筛子筛下来剩下的就是真正扛打的命令。2.1 故障场景覆盖率从“现象-动作-验证”闭环出发我们统计了近三年所有P1/P2级事件的根因分布发现83%的问题集中在五个象限资源耗尽类CPU/内存/磁盘IO/网络连接/文件句柄进程失控类僵尸进程/孤儿进程/高CPU线程/内存泄漏网络异常类端口占用/路由错误/防火墙拦截/DNS解析失败存储故障类inode耗尽/磁盘坏道/挂载异常/LVM卷组离线权限与配置类SELinux上下文错乱/ACL策略冲突/systemd单元文件语法错误每条入选命令必须能精准切入至少一个象限并形成最小闭环。例如针对“磁盘IO飙升”单纯iostat -x 1只能告诉你%util达到100%但无法定位是哪个进程在刷盘。这时必须组合iotop -oP只显示实际IO进程pidstat -d 1按PID统计IO吞吐lsof -p {pid} | grep REG查看该进程打开的文件类型。这三条命令构成完整证据链iotop发现java进程IO等待高达98%pidstat确认其读写速率达120MB/slsof则显示它正持续向/var/log/app/trace.log追加写入——最终查明是某开发误将DEBUG日志级别设为全局生效。如果只列iostat就等于只给了半张X光片。提示所有覆盖多象限的命令都标注了“主攻方向协同命令”。比如strace -p {pid} -e tracewrite,open,connect本身属于“进程失控类”但当它捕获到connect(3, {sa_familyAF_INET, sin_porthtons(53), ...}) -1 EINPROGRESS时立刻切换到“网络异常类”分析路径此时需同步运行nslookup example.com和cat /etc/resolv.conf交叉验证。2.2 资源消耗阈值在“能用”和“敢用”之间划红线很多命令在测试环境很优雅一上生产就变炸弹。典型如find / -name *.log -mtime 30——在千万级文件的系统里它会吃光所有可用inode缓存导致后续ls命令延迟超10秒。我们设定硬性阈值单条命令默认执行时间不超过3秒内存占用峰值不超50MB且不产生任何临时文件或后台守护进程。这就解释了为何fdisk -l被剔除而lsblk -f入选前者需读取全盘扇区信息在10TB RAID阵列上耗时可达47秒后者仅解析内核块设备树平均响应0.2秒。同理du -sh /var/*在/var含大量Docker镜像层时极易卡死而ncdu -x /var需预装采用增量扫描内存映射实测在相同环境下耗时稳定在1.8秒内。更关键的是ncdu支持交互式钻取——按→进入子目录按d删除选中项按q退出不保存完全规避了rm -rf误操作风险。对于必须高开销的诊断场景我们强制要求前置保护措施。例如tcpdump抓包绝不允许tcpdump -i any port 80这种裸奔操作必须限定-c 1000抓1000个包后自动退出指定-w /tmp/capture.pcap写入临时文件而非stdout并添加-G 300每5分钟轮转一次。这样即使忘记终止5分钟后也会自动停写避免/tmp被撑爆引发连锁故障。2.3 人机交互效率让手指少移动让大脑少切换运维不是编程没有IDE自动补全。在压力场景下每多敲一个字符、每多看一眼屏幕、每多切换一次窗口都可能延长故障时长。我们用“Fitts定律”量化交互成本目标越小、距离越远、反馈越慢操作失误率越高。因此journalctl -u nginx --since 1 hour ago | grep -i failed被优化为journalctl -u nginx -S 1h ago | grep -i failed——-S替代--since省2个字符|合并stderr/stdout避免漏掉关键错误failed不加引号因grep默认支持空格分隔。再比如df -hT | grep xfs在XFS为主力文件系统的环境中直接固化为别名alias dfxdf -hT | grep xfs输入dfx即可获得定制化视图。这些细节看似微小但在连续处理5个告警的深夜累计节省的注意力相当于多出一轮完整思考周期。注意所有需要预装的工具如ripgrep、exa、bat都附带一行安装命令且明确标注适用场景。例如rg -tjs fetch.*error /opt/app/src/比grep -r fetch.*error /opt/app/src/ --include*.js快17倍但仅当代码库超10万行时才值得引入——小项目用原生grep更稳妥。3. 真实故障链路中的命令组合术命令单用是工具组合起来才是武器。我整理了7类高频故障的“黄金组合链”每条链都经过至少20次线上验证。它们不是固定公式而是根据实时反馈动态调整的决策树。下面以“服务突然502 Bad Gateway”为例展示如何用12条命令在8分钟内完成全链路定位。3.1 第一阶段确认现象边界0-90秒故障永远始于现象确认。此时严禁盲目重启必须用最轻量命令划定影响范围# 1. 确认本机Nginx是否存活且监听 systemctl is-active nginx ss -tuln | grep :80\|:443 # 2. 检查上游服务假设是Node.js API是否可达 curl -I http://localhost:3000/health 2/dev/null | head -1 # 3. 快速扫描最近10分钟错误日志关键词 journalctl -u nginx --since 10 minutes ago | grep -E (502|upstream|timeout|connect) | tail -5这三步的核心逻辑是先验本地状态再验依赖连通性最后扫日志线索。如果第1步失败说明Nginx自身异常跳转至“进程失控类”排查如果第2步失败问题在上游立即执行systemctl status node-api如果第3步出现upstream timed out则进入网络层深挖。实操心得journalctl加--since参数必须用英文单位10 minutes ago不能写10m ago否则返回空。这个坑我踩过三次每次都在凌晨三点。3.2 第二阶段网络层穿透诊断90-180秒当确认Nginx存活但上游不通时需排除网络中间件干扰# 4. 查看Nginx upstream配置指向的实际地址 grep -A 5 upstream backend /etc/nginx/conf.d/app.conf # 5. 测试该地址的端口连通性绕过DNS timeout 3 bash -c echo /dev/tcp/10.0.2.5/3000 echo OK || echo FAIL # 6. 若FAIL检查本机到该IP的路由路径 mtr -r -c 5 10.0.2.5 | grep -E (Host|Loss) # 7. 同时抓取Nginx worker进程的网络调用 strace -p $(pgrep -f nginx: worker) -e traceconnect,sendto,recvfrom -s 100 -o /tmp/strace.log 2/dev/null 这里的关键设计在于多线程并行取证步骤5、6、7同时执行互不阻塞。timeout 3 bash -c echo /dev/tcp/...比telnet更可靠因为它不依赖终端交互模式mtr比traceroute多提供丢包率统计能快速判断是单点故障还是链路拥塞strace后台运行避免中断当前操作其输出文件/tmp/strace.log后续可精读。3.3 第三阶段上游服务深度剖析180-420秒若网络层通畅问题必在上游服务内部。此时需获取其运行时快照# 8. 获取上游进程的资源占用详情 pidstat -p $(pgrep -f node server.js) 1 3 # 9. 检查其打开的文件描述符数量 lsof -p $(pgrep -f node server.js) | wc -l # 10. 抓取其JVM堆内存快照若为Java服务则换jmap jstack $(pgrep -f node server.js) /tmp/jstack.out 21 # 11. 分析其最近1分钟的GC日志若有 tail -n 100 /var/log/node-app/gc.log | grep -E (Full GC|Allocation Failure) # 12. 最终验证模拟Nginx请求头发起直连 curl -H Host: app.example.com http://10.0.2.5:3000/api/v1/status步骤12是终极验证——它复现了Nginx转发请求的全部特征Host头、路径、协议如果此处成功而Nginx返回502基本锁定为Nginx配置问题如proxy_set_header未透传必要头如果此处也失败则上游服务确已崩溃需结合步骤8-11的资源数据判断是OOM还是死锁。踩坑实录某次故障中pidstat显示CPU使用率仅12%但lsof统计文件描述符达65423超系统限制65535。原来是个HTTP客户端未关闭连接池导致TIME_WAIT状态堆积。解决方案不是重启而是ss -s | grep TCP:确认连接数再用ss -tnp | grep :3000 | awk {print $7} | cut -d, -f2 | sort | uniq -c | sort -nr找出恶意客户端IP最后通过iptables限流——整个过程未动应用代码。4. 那些被低估的“冷门但致命”的命令细节有些命令看似简单但参数组合的微妙差异足以决定故障定位是5分钟还是5小时。我把这些经验浓缩成“参数黄金法则”每一条都对应一个血泪教训。4.1ps命令别再用aux试试eo pid,ppid,comm,%cpu,%mem,vsz,rss,tty,stat,time,cmdps aux是新手最爱但它输出字段过多11列且%cpu和%mem是采样值瞬时波动大。我们团队统一使用定制化格式# 标准化进程视图按CPU降序 ps eo pid,ppid,comm,%cpu,%mem,vsz,rss,tty,stat,time,cmd --sort-%cpu | head -10 # 关键字段解读 # vsz virtual memory size虚拟内存含共享库 # rss resident set size物理内存真正占用RAM # stat 进程状态R运行 S睡眠 Z僵尸 高优先级 N低优先级这个格式的价值在于同时暴露父子进程关系ppid、内存真实占用rss、进程健康状态stat。曾有个案例ps aux显示某Python进程CPU 99%但ps eo揭示其stat列为 R高优先级运行中而rss仅12MB——说明它在做纯计算非IO阻塞。进一步用perf top -p {pid}发现是正则表达式回溯爆炸最终优化正则模式解决。提示ps的--sort参数支持多级排序如--sort-%cpu,vsz表示先按CPU降序CPU相同时按vsz升序。这对识别“CPU低但内存疯涨”的泄漏进程极有用。4.2ss命令-tuln只是起点-i和-e才是破案关键ss -tuln能看端口监听但无法解释“为什么连接建立后立刻断开”。这时必须启用TCP详细信息# 查看指定端口的TCP连接详细状态含重传、拥塞窗口等 ss -tulni | grep :8080 # 输出关键字段 # rto: 重传超时时间正常200ms若1000ms说明网络质量差 # rtt: 往返时延RTT variance高意味着抖动严重 # cwnd: 拥塞窗口大小突降至1表示遭遇丢包 # retrans: 已重传次数持续增长说明链路不稳定某次CDN回源失败ss -tuln显示8080端口正常监听但ss -tulni暴露出cwnd:1和retrans:127——根源是IDC机房到云厂商BGP线路出现微突发丢包运营商在2小时内修复。若只看基础端口状态会误判为应用层问题。4.3journalctl命令-o json-pretty配合jq实现日志结构化分析原始日志是文本洪流必须结构化才能高效挖掘。journalctl原生支持JSON输出# 导出最近1小时Nginx错误日志为JSON journalctl -u nginx --since 1 hour ago -o json-pretty /tmp/nginx.json # 用jq提取关键字段status码、request_uri、upstream_addr cat /tmp/nginx.json | jq -r select(.PRIORITY3) | \(.SYSLOG_IDENTIFIER) \(.MESSAGE) \(.SYSLOG_TIMESTAMP) | head -10 # 统计各status码出现频次 cat /tmp/nginx.json | jq -r .MESSAGE | capture(status(?status\\d)) | .status | sort | uniq -c | sort -nr这种方法比grep -o status[0-9]*准确十倍因为jq能精确匹配JSON字段不受日志文本中其他数字干扰。我们甚至用它构建了自动化日报每天凌晨3点执行journalctl -u nginx --since 24 hours ago -o json | jq [.[] | select(.PRIORITY3)] | length若错误数超阈值则自动发钉钉告警。4.4find命令-printf替代-exec ls -l实现零延迟遍历find /var/log -name *.log -mtime 7 -exec ls -l {} \;在百万文件目录下会启动百万次ls进程耗时以小时计。正确姿势是# 单次进程完成所有输出 find /var/log -name *.log -mtime 7 -printf %M %u:%g %10s %TY-%Tm-%Td %TH:%TM %p\n | sort -k6,6 | head -10 # 格式化字符串详解 # %M 权限如drwxr-xr-x # %u:%g 用户:组 # %10s 文件大小右对齐10字符 # %TY-%Tm-%Td 修改年-月-日 # %TH:%TM 修改时:分 # %p 完整路径这个技巧让我们在某次磁盘清理中将find耗时从42分钟压缩到3.7秒。更妙的是-printf输出天然适配sort和awk无需额外解析。5. 从“会用”到“精通”的认知跃迁掌握100条命令只是起点真正的分水岭在于理解“命令背后的操作系统契约”。我总结了三个认知跃迁点每个点都对应一次职业突破。5.1 跳出“命令即功能”的思维牢笼建立“系统调用-内核模块-用户态工具”映射df命令显示磁盘使用率但它的数据来源是statfs()系统调用该调用读取的是VFS虚拟文件系统层的超级块信息。当你执行df -h时实际发生的是df进程调用statfs(/home)→内核VFS层查询/home挂载点的struct super_block→从中提取s_blocks总块数、s_bfree空闲块数、s_bavail可用块数 →用户态计算百分比并格式化输出这个链条揭示了一个关键事实df显示的“可用空间”不等于du统计的“已用空间”因为s_bavail会预留5%给root用户ext4默认而du只统计文件实际占用。所以当df显示95%满而du只统计到88%时不是命令错了是内核的预留策略在起作用。解决方案是tune2fs -m 1 /dev/sdb1将预留空间降至1%或用df -h --total查看全局统计。个人体会我在某次处理“磁盘满但找不到大文件”问题时正是靠这个认知发现/var/log/journal目录被systemd-journald占满而du -sh /var/log/journal却显示仅2GB——因为journal日志启用了SystemMaxUse1G但RuntimeMaxUse500M实际磁盘占用受两个参数共同约束。最终用journalctl --disk-usage查清真相。5.2 理解“一切皆文件”的哲学把设备、进程、网络抽象为可操作对象Linux中/proc和/sys是通往内核的窗口。/proc/{pid}/fd/目录下的每个数字都是一个打开的文件描述符ls -l /proc/1234/fd/能看到它指向的真实文件或socket/sys/class/net/eth0/statistics/下的tx_bytes和rx_bytes是网卡收发字节数的实时计数器。这意味着你可以不用ifconfig直接cat /sys/class/net/eth0/address获取MAC地址或用echo 1 /sys/class/net/eth0/device/remove热拔网卡慎用。这种抽象能力让我们在容器环境中游刃有余。例如排查Kubernetes Pod网络不通先kubectl exec -it pod-name -- sh进入容器执行ip link show发现eth0状态为DOWN查cat /proc/1/net/dev确认无流量最终ls -l /proc/1/ns/net发现它指向宿主机网络命名空间net:[4026532000]而正常Pod应指向独立命名空间net:[4026532510]——根源是CNI插件未正确注入网络配置。5.3 接受“不确定性”用命令构建概率化决策模型运维没有100%确定的答案只有概率化判断。vmstat 1输出的siswap in和soswap out值若持续100大概率是内存不足但若free -h显示available仍超2GB则可能是内核内存管理策略激进如swappiness60。此时需交叉验证cat /proc/sys/vm/swappiness确认值grep -i out of memory /var/log/kern.log检查OOM Killer日志sar -r 1 10观察%memused趋势我们团队将这种思维固化为“三指标交叉法”任一指标异常即触发告警但根因判定必须满足至少两个指标同向变化。例如CPU使用率90%且runq-sz运行队列长度4才判定为CPU瓶颈若仅CPU高而runq-sz1则可能是单线程计算密集型任务无需干预。最后分享一个小技巧把最常用的10条命令固化为~/.bashrc别名并添加注释说明适用场景。例如# 快速定位高IO进程生产环境首选 alias iotop-highiotop -oP -n 1 # 安全删除大日志保留最新100MB避免rm -rf误伤 alias safe-log-cleanfind /var/log -name *.log -size 100M -exec truncate -s 100M {} \; # 一键生成服务健康报告含进程、端口、日志、资源 alias svc-reportecho Process ; pgrep -f myapp | xargs ps -o pid,ppid,%cpu,%mem,vsz,rss,comm; echo Ports ; ss -tuln | grep :80\|:443; echo Logs ; journalctl -u myapp --since 5 minutes ago | tail -5; echo Resources ; free -h; df -h这些别名不是偷懒而是把经验封装成肌肉记忆。当你在第三次凌晨处理同类故障时手指会自动敲出svc-report而大脑已开始思考下一步——这才是100条命令的终极价值把重复劳动压缩成0.5秒的击键把宝贵的认知资源留给真正需要创造的地方。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑