ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux常用命令实战:从进程管理到故障排查的必备手册

Linux常用命令实战:从进程管理到故障排查的必备手册 这篇是 Linux 常用命令系列的第十四篇。写到这一篇我越来越觉得命令这东西真不是靠死记硬背就能用得好的而是要在实际排查、部署、调优的过程里反复用到手指才会形成肌肉记忆。这一篇我打算把日常运维和开发中命中率最高的几类命令挑出来聊进程管理、磁盘文件、文本处理、网络诊断、服务与容器以及一些真正踩过坑之后总结出来的排障思路。如果你正在从会敲几条命令往“能独立处理问题”的方向走这篇值得仔细看看。命令不在多关键是用对地方。1. 进程管理先把系统里正在发生的事情看清楚排查问题的第一步永远是搞清楚“当前系统里到底在跑什么”。很多新手上来就喜欢ps aux看一堆输出然后只盯着 COMMAND 那一列。说实话ps aux给的信息量非常大如果你只会看进程名那等于只看了一页报表的标题真正有用的细节全被忽略掉了。1.1 看懂 ps 输出里的那些关键字段ps aux的输出长这样USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 168296 13548 ? Ss 09:30 0:01 /usr/lib/systemd/systemd这里面的 VSZ 和 RSS 值得多说一句。VSZ 是虚拟内存大小指的是进程声明自己需要的地址空间不等于真的用了这么多物理内存RSS 才是真正常驻物理内存的大小。所以你看一个进程占用内存高不高优先看 RSS而不是被 VSZ 吓到。比如 Java 进程的 VSZ 动辄几个 G但 RSS 可能只有几百 M就是因为 JVM 预留了大片堆外地址空间不代表物理内存爆了。STAT 这一列是很多人忽略的重点。它是组合状态码第一位是主状态R运行中、S可中断睡眠、D不可中断睡眠通常是等待 IO、Z僵尸进程、T停止。第二位及以后是附加信息小写s表示该进程是会话首进程l表示多线程表示在前台进程组里。几个实战命中率很高的用法找出僵尸进程ps -ef | awk $8Z。僵尸进程杀不掉只能杀它的父进程或者等父进程回收。查看某进程的所有线程ps -eLf | grep javaLWP 列就是线程 ID线程排查时非常关键。按内存或 CPU 排序找出头几名ps aux --sort-%mem | head -20或--sort-%cpu比人眼扫描整个列表高效得多。另外pgrep -fl 进程名可以直接拿到 PID 和完整命令行pidof 进程名也能快速找 PID比ps -ef | grep后面再手动过滤 grep 本身干净很多。我建议你把这些当成习惯省掉每次那条grep -v grep的尾巴。1.2 top 的正确打开方式别只盯着 load averagetop是进程监控的标配但真正会用的人不多。进去之后第一件事我建议按1展开每个 CPU 核的使用情况。如果服务器是 8 核而%Cpu(s)显示的整体使用率只有 12%但你感觉服务很卡这时候单核 100% 的情况很容易被平均值掩盖按1能立刻看出来是不是只有某个核被打满。再记住三个排序快捷键按P按 CPU 排序按M按内存排序按T按累计 CPU 时间排序。T这个容易被忽略但它能找出那种“当前 CPU 不高但已经累计消耗了大量 CPU 时间”的进程往往就是泄漏的元凶。top里还有一个字段叫TIME是进程累计消耗的 CPU 时间。如果你重启服务后没过多长时间这个值就变得非常大说明这个进程大概率陷入了异常循环或者计算密集型的死循环。真正让我觉得top还不够用的时候是定位 Java 进程 CPU 飙高的场景。完整的套路是这样的# 1. 找到 Java 进程 PID jps 或 pgrep -f java # 2. 用 top -H 打开线程视图只看这个进程 top -H -p PID # 3. 找到 CPU 最高的线程号比如 28476转成十六进制 printf %x\n 28476 # 输出 6f3c # 4. 用 jstack 抓线程栈搜 nid0x6f3c jstack PID | grep -A 30 nid0x6f3c这样就能定位到具体业务代码在哪一行。这套流程在线上排查 CPU 问题时非常有效比盲目重启服务科学得多。如果你连线程栈都看不懂那至少能定位到是哪个线程在忙再针对性地看代码。load average三个值也要会读。它分别代表 1 分钟、5 分钟、15 分钟的平均负载。如果 15 分钟值很高而 1 分钟值降下来了说明峰值正在过去如果三个值都高说明系统持续过载。但注意负载高不一定 CPU 忙还可能是大量进程处于D状态也就是在等待磁盘 IO。这时候看top会发现 CPU idle 还很高但进程全堵在 IO 上这就是典型的存储瓶颈。1.3 kill 不是随便杀信号和优雅退出很多新人最爱的就是kill -9 PID因为省事。但-9是 SIGKILL内核直接强制回收进程不给进程任何清理现场的机会。你正在写一半的文件、正在提交的事务、临时文件都可能被搞坏。正确的姿势是先用默认的kill PID也就是 SIGTERM通知进程“该收工了”让进程自己处理善后然后退出。只有等了很久进程仍然不退再考虑kill -9。几个常用的变体killall 进程名按名字杀一批进程但要小心名字匹配过宽。pkill -f 匹配串按完整命令行匹配能杀掉命令行里包含特定路径的进程。pkill -u 用户名杀掉某个用户的所有进程。后台任务这块我见过太多人写nohup xxx 然后关终端结果进程还是死了。nohup的作用是让进程忽略 SIGHUP 信号终端挂断时不随之退出是把进程放到后台。两个要配合用缺一个都可能出问题。更现代一点的做法是用systemd-run --unitxxx --propertyRuntimeMaxSec...来托管一次性任务日志也统一由 journald 管理比 nohup 的输出重定向体验好很多。systemctl在日常运维里的地位已经不可替代。常用的组合是systemctl status nginx # 看状态 systemctl reload nginx # 重新加载配置不中断服务 systemctl restart nginx # 重启 systemctl enable --now nginx # 设置开机自启并立即启动 systemctl list-unit-files --stateenabled # 查看所有开机自启项reload和restart的区别一定要分清。nginx、php-fpm 这类进程支持 reload也就是平滑重载配置已建立的连接不断。但有些服务它的 reload 其实是先停后起和 restart 没区别你在执行之前最好先看一眼文档别想当然。2. 磁盘与文件系统空间不会凭空消失只会换了地方藏着磁盘告警是运维里最常遇到的故障之一。df -h一看使用率 95%很多人的第一反应就是找大文件删。但真正的坑往往在“删了文件之后空间并没有释放”这种情况我一年能遇到好几次。2.1 df 与 du 组合别让僵尸文件把磁盘堵死df -h看的是文件系统的整体使用情况du看的是目录和文件实际占用。很多人不知道还有一个容易忽视的df -i它看的是 inode 使用率。inode 是每个文件或目录的索引节点如果一个分区上的小文件数量爆炸即使磁盘空间还有富余也可能报No space left on device。我遇到过一台机器就是某个服务疯狂生成几十万个空文件把 inode 耗光了。所以排查磁盘问题第一步永远是df -h和df -i两个都看一眼。定位大目录的标准操作du -h --max-depth1 / 2/dev/null | sort -rh | head -20sort -rh是关键-h让人读懂的大小单位-r倒序这样最大的目录会排在最上面。逐层往下查很快能锁定空间被谁吃掉了。最经典的坑是“文件删了空间没回来”。背后的原理其实很简单某个进程还在持有这个被删除文件的文件描述符。Linux 下文件是否占用磁盘空间取决于有没有进程打开着它。解决方法是lsof L1 | grep deletedL1的含义是列出 link count 为 0 且仍被进程占用的文件。查到之后找到对应的 PID确认业务影响后重启或 kill 那个进程空间才会真正释放。更极端的场景如果你找不到是哪个进程可以搜/proc/*/fd/*里的符号链接指向(deleted)的记录再反查进程号。这个知识点在面试里也经常作为加分题出现因为它能看出一个人是背命令还是真正理解文件系统的行为。磁盘操作还有一条铁律别在不知道后果的情况下用rm -rf。我自己的习惯是命令里凡是涉及rm -rf的都会先ls确认目标目录再执行。生产环境更推荐用一个回收目录mkdir -p /trash mv /path/to/target /trash/然后定期清理/trash。这样误删了还有反悔的机会比rm直接不可恢复稳妥得多。另外提醒一句aliasrmrm -i只在交互式 Shell 里生效脚本里压根不会执行 alias所以千万别把靠 alias 保平安当成生产环境的安全策略。2.2 挂载操作从裸盘到业务可用的完整路径新加一块数据盘从裸设备到正常使用步骤并不复杂但每一步都有讲究。先看设备lsblk # 输出里 NAME、SIZE、TYPE、MOUNTPOINT 是最重要的 blkid /dev/vdb # 拿到 UUID后面写 fstab 要用然后格式化注意确认盘符千万别把系统盘给格了mkfs.ext4 /dev/vdb1挂载到目录mkdir -p /data mount /dev/vdb1 /data但这里有个坑直接用/dev/vdb1挂载重启后设备名可能漂移。所以我强烈建议写进/etc/fstab时用 UUID而不是设备名。/etc/fstab每行六列设备、挂载点、文件系统类型、挂载选项、是否 dump、是否 fsck。例如UUIDxxxx-xxxx-xxxx /data ext4 defaults 0 2写完fstab后一定先执行mount -a验证配置无误再重启。如果 fstab 写错导致起不来系统在单用户模式里把那一行注销掉是常规补救操作这个经验希望大家永远用不到但要知道有这回事。挂载远程存储也很常见。NFS 方式mount -t nfs -o rw,sync,vers4 192.168.1.10:/export /mnt/nfsCIFS 方式访问 Windows 共享mount -t cifs -o usernamebackup,passwordxxx //192.168.1.20/share /mnt/cifs生产环境的fstab里远程挂载建议加_netdev选项意思是等网络就绪后再挂载否则开机时网络还没起挂载失败会拖慢启动甚至导致服务异常。磁盘扩容后的处理也容易踩坑。云服务器控制台里扩完容量进系统df -h还是原来的大小这是正常的因为分区表还没变。需要先lsblk查看磁盘容量是否已变大然后对分区进行扩容最后对文件系统扩容。ext4 用resize2fs /dev/vdb1xfs 用xfs_growfs /data。xfs 只能扩容不能缩容选文件系统之前要想清楚未来是否需要缩容。3. 文本处理与日志分析把藏在日志里的线索捞出来做运维和开发一天到晚打交道最多的就是文本。日志、配置、接口返回、脚本输出全是文本。文本处理三剑客grep、sed、awk用得好排查效率是几何级提升。3.1 grep 的花式用法从搜索到提取grep最基本的用法是搜关键字比如grep ERROR app.log但在日志量大到几 GB 的时候全量搜完要等很久。我建议配合-m参数限制匹配行数先拿到前几条确认内容再决定要不要继续搜grep -m 10 java.lang.NullPointerException app.log只看报错上下文用-A和-B后面接行数grep -A 5 -B 3 Caused by: app.log大多数时候报错原因在Caused by后面的几行里单独把异常信息摘出来比看整屏堆栈高效得多。-o参数是我觉得最被低估的。它只输出匹配到的部分而不是整行。配合正则表达式可以从日志里批量提取 IP、订单号、耗时数值# 提取日志里所有 IPv4 地址 grep -oE [0-9]{1,3}(\.[0-9]{1,3}){3} access.log | sort | uniq -c | sort -rn后面接的sort | uniq -c | sort -rn是一套高频组合它的意思是“排序 → 去重并统计次数 → 再按次数倒序”。这一串在统计访问量 TOP IP、错误码分布、关键字频率时是神兵利器。举个例子你想知道日志里出现最多的 10 个具体异常grep -oE java\.lang\.[A-Za-z]Exception app.log | sort | uniq -c | sort -rn | head -10grep过滤干扰信息也很有用。日志里如果有大量健康检查请求可以用grep -v排除掉这样就干净多了。grep -v healthcheck app.log | grep ERROR-v是反向匹配它和管道组合起来能帮你从海量噪音里精准锁定目标。3.2 sed 与 awk批量改文件、统计字段的实战姿势sed最常见的用途是批量替换。注意它默认不会修改原文件只会输出到标准输出要真正改文件需要加-i参数。我自己的习惯是替换前先备份# 把配置文件里的旧 IP 批量替换为新 IP备份为 .bak sed -i.bak s/192.168.1.100/10.0.0.100/g /etc/conf/*.properties如果替换内容里有斜杠/会导致命令变得难读这时候可以把分隔符换成#或|sed -i s#/old/path#/new/path#g filesed -n 20,30p file可以打印指定范围行在看大文件中间某段时很好用比head/tail灵活得多。sed /^#/d file能删除所有以#开头的注释行在整理配置文件时非常实用。awk的核心能力是“按列处理”。默认按空白符分隔$1是第一列$NF是最后一列。比如从访问日志里统计每个状态码的数量一行命令就能完成awk {print $9} access.log | sort | uniq -c | sort -rn这里的列号取决于日志格式可能是$9也可能是$10你可以先用head -1 access.log确认再定列号。awk 内部还能做条件判断和累加。比如统计某时间段的请求总量awk $4 01/Feb/2025:12:00:00 $4 01/Feb/2025:13:00:00 {count} END {print count} access.log这种复杂逻辑用grep很难优雅实现awk 天生就是干这事的。再比如统计一行日志里的平均响应时长假设最后一列是耗时毫秒awk {sum $NF; count} END {print sum/count} api.logawk还有一个高频姿势是按分隔符提取文件内容。比如/etc/passwd用冒号分隔要取用户名列表awk -F: {print $1} /etc/passwd文本三剑客各自擅长的事不太一样grep用于筛选行sed用于按行处理替换awk用于按列统计。现实工作中它们经常组成管道链比如先用grep把无关行过滤掉再喂给awk做统计这样写出来的命令短小精悍可读性也好。4. 网络诊断与连通性排查别一上来就甩锅给机房网络问题是最容易让人头皮发麻的一类故障。但要记住一句话网络排查是分层递进的不是瞎猜的。不会用工具链的人只会 ping 一下能通就说网络好的不能通就干瞪眼。真正的排查顺序应该是连通性 → 路由 → DNS → 端口 → 应用协议。4.1 ping 通不代表服务可用ping 不通也不代表网络真断了很多人把 ping 当成了网络是否健康的唯一指标。实际上 ping 用 ICMP 协议测的是主机是否可达而很多云环境和安全策略本身就会禁用 ICMP所以“ping 不通”不一定就是网络真断了也可能是对方不回应 ICMP 探测。正确的第一步是ip addr确认本机 IP 配置再用ip route看默认路由是否正常。然后 ping 一个已知的稳定地址判断基础连通性。如果本机可以上网但访问某个内网服务器不通用traceroute -n看每一跳的延迟和丢包能快速判断故障点是在本机网关、运营商链路还是目标主机。DNS 是另一个高频故障点。域名解析不出来、解析到错误 IP都会造成“网络好像有问题”的错觉。排查时用getent hosts 域名、nslookup 域名或dig 域名确认解析结果是否符合预期。还要检查/etc/resolv.conf里的 nameserver 配置有时候系统装了systemd-resolved后这个文件会被自动指向 127.0.0.53这本身不是问题但如果你手动改过这个文件而没重启相关服务可能不生效。4.2 ss、nc、curl端口与服务排查组合拳当网络层是通的、DNS 正常但业务仍然不可用问题基本出在 TCP 端口或应用层。检查本机端口监听状态我强烈建议直接用ss而不是老的netstat。ss输出更快信息更全语法也兼容。# 查看某个端口是否在监听以及是哪个进程在监听 ss -tlnp | grep :3306 # 查看所有 TCP 连接显示进程名 ss -tunap输出里LISTEN状态表示有服务在监听ESTABLISHED是已建立的连接TIME_WAIT是主动关闭方等待回收的连接。如果端口大量处于TIME_WAIT在短连接高并发的场景下是正常的但如果特别夸张可能需要调整内核参数这属于另一个话题了。测试端口通不通telnet是最直观的但脚本环境下nc更好用nc -vz -w3 192.168.1.10 3306-v输出详细信息-z只扫描不发送数据-w3超时 3 秒。返回succeeded说明端口通refused或超时说明不通。请求 HTTP 接口排查服务状态curl是万能的curl -sS -m 5 -I https://example.com/api/health curl -sS -o /dev/null -w %{http_code}\n https://example.com/api/health-I只拿响应头节省流量-w可以自定义输出%{http_code}表示 HTTP 状态码。用这个组合可以快速判断接口是 5xx、4xx 还是 200。如果 curl 带了代理环境变量-noproxy可以禁止代理请求本机服务时经常要用到。再补一个常见故障服务起不来提示端口被占用。排查链路是ss -tlnp | grep 端口 # 拿到 PID 后确认是什么进程 ps -fp PID # 确认是旧进程残留就正常终止终止不了再考虑 kill -9如果你用了 systemd 管理服务建议systemctl status看一眼再journalctl -u 服务名 -n 50看最近日志很多时候日志已经告诉你为什么失败了。5. 服务、容器与调试现代环境下的命令迁移现在几乎很少有人在裸机上直接装应用了要么 systemd 管服务要么容器化部署要么虚拟化平台。命令体系也跟着场景产生了变化但底层的排查逻辑没变。5.1 journalctl把所有日志收拢到一个入口systemd 时代的服务日志用journalctl统一查看体验比翻 /var/log 里的文件强太多。最常用的几招# 看某个服务的最近日志 journalctl -u nginx -n 100 # 实时跟踪 journalctl -u nginx -f # 看最近一小时内的错误级别日志 journalctl -u nginx --since 1 hour ago -p err # 看本次开机后的系统日志里和磁盘相关的内容 journalctl -k | grep -i disk-p err按日志级别过滤-k只看内核日志这两个参数能让排查范围快速缩小。journald 的日志如果放任不管也会积累出巨大的磁盘占用量。维护命令是journalctl --vacuum-size200M journalctl --vacuum-time7d这个行为可以直接写进 crontab 定期执行或者在/etc/systemd/journald.conf里配置SystemMaxUse限制上限比事后清理更优雅。5.2 容器内排查docker 命令的常用习惯容器化之后排查问题的思路从“看进程”变成了“看容器”。Docker 常用的命令并不复杂但组合起来可以覆盖绝大多数场景docker ps -a # 看所有容器包括退出的 docker logs --tail 100 容器名 # 看容器日志-f 可以跟踪 docker exec -it 容器名 bash # 进入容器 docker inspect 容器名 # 查看容器配置细节 docker stats # 看容器资源占用 docker top 容器名 # 看容器内进程容器内排查有个容易懵的点容器里ps往往看到 PID 1 是主进程其他进程需要进入容器才能看到。如果某个容器一直重启先把docker logs拿到再docker inspect看RestartPolicy和ExitCode这些信息基本能定位大部分问题。还有一个很实用的技巧docker inspect的输出是 JSON 格式可以用jq精确提取字段比如查看容器挂载了哪些目录docker inspect 容器名 | jq .[0].Mounts在 KVM 虚拟化环境里virsh是命令主力virsh list --all # 列出所有虚拟机 virsh start 虚拟机名 # 启动 virsh shutdown 虚拟机名 # 优雅关机 virsh destroy 虚拟机名 # 强制断电慎用 virsh console 虚拟机名 # 进入虚拟机 consolevirsh destroy等同直接拔电源非必要不要用。这和kill -9的逻辑一样先优雅、再强制。5.3 定位崩溃现场gdb 与开发侧常用命令如果你手头有一个正在运行的进程卡死了可以用gdb -p PID附加到进程上看它的当前调用栈。这个操作在生产环境要小心有时会因 ptrace 限制而失败。更轻量的选择是用pstack或/proc/PID/stack查看内核栈。Java 生态则用jstack前面已经演示过。gdb配合 core dump 文件也很常用。进程崩溃时如果系统配置了 core dump会生成一个 core 文件然后可以gdb ./your_binary /path/to/core进入 gdb 后输入bt打印崩溃时的调用栈崩溃现场就一目了然了。排查完了quit退出。开发日常里git命令的调试定位能力同样关键git log --oneline --graph # 看清提交历史分支 git blame 文件 # 某一行到底是哪次提交引入的 git bisect start # 二分定位坏提交git bisect虽然不常用但遇到“最近一次更新后功能突然挂了”的经典场景比人肉翻提交记录高效几个数量级。6. 常见的坑与我的排障习惯写到这里我想把一些真正从现场总结出来的经验和常见坑集中整理一下。这些内容也许不是一个具体的命令但比具体命令更值钱因为它们能帮你少走弯路。6.1 一个典型的磁盘告警案例复盘有一次线上服务器报磁盘使用率 95%我按常规流程排查先df -h确认/分区确实快满了然后du -h --max-depth1 / 2/dev/null | sort -rh | head找到罪魁祸首是一个日志目录里面躺着一个十几个 GB 的过大日志文件。当时我以为rm掉它就能解决结果删完df -h一看使用率还是 95%一点没变。那一刻反而冷静了立刻想到是不是有进程还握着这个文件句柄。执行lsof L1 | grep deleted果然那个日志文件被一个还在跑着的服务进程占着。因为服务没有重启文件虽然从目录里删了但磁盘空间并没有释放。最终确认业务影响窗口后重启了服务空间立刻回归正常。这个案例里有两条教训。第一条删除被进程占用的文件前一定要考虑句柄引用问题尤其是日志类文件。第二条日志管理应该用logrotate按天按大小切割保留最近若干份而不是等它长到失控再去手动删。很多线上事故本质上是没把工具的机制想透只记住了命令表面的效果。6.2 面试里常见的命令题怎么答才加分面试时常见的一类问题就是“这个场景用什么命令”。如果只是背命令面试官随便一追问就露馅。更好的思路是把命令当成排查链条的一环来回答。我把几个高频问题整理成了速查表面试场景核心命令加分回答查看端口被哪个进程占用ss -tlnp说明先看监听状态再定位进程而不是直接 kill找出 CPU 占用最高的进程top按 P 排序或ps aux --sort-%cpu补充线程级排查思路如top -H -p PID磁盘满了怎么办df -h、df -i、du -h --max-depth1补充 inode 耗尽和已删除未释放的坑这是加分点统计日志里次数最多的 IPawk {print $1} log | sort | uniq -c | sort -rn解释先按列提取再去重计数最后排序批量改配置文件sed -i.bak s/old/new/g file强调备份参数-i.bak和修改前确认查看开机自启服务systemctl list-unit-files --stateenabled能区分 enable 状态和当前运行状态服务起不来怎么查journalctl -u 服务名 -n 50强调看日志而不是盲目 restart回答这些问题的关键不是把命令完整背出来而是要让面试官感觉到你清楚每一个参数的含义以及命令执行结果的下一步动作是什么。比如“查看端口占用”你拿到 PID 之后会怎么处理这决定了你是背命令还是真做过。6.3 把命令固化成日常习惯最后分享一个我自己非常受用的习惯把高频命令做成年份都不过时的备忘录而不是每次临时man。我会在~/bin下放一些自己写的脚本把复杂的管道组合固化成一个命令。比如统计访问日志里 TOP 10 IP我会写个脚本存起来而不是每次敲一整串管道。再推荐两个提升效率的小配置。一个是在~/.bashrc里设置好用的 aliasalias llls -lhF --time-stylelong-iso alias dfdf -h alias dudu -h --max-depth1 alias grepgrep --colorauto # 用历史命令最后一段参数 alias lastarg!$另一个是快捷键。CtrlR反向搜索历史命令CtrlW删除前一个单词CtrlU清空整行CtrlE跳到行尾。这些操作每一次省下的时间可能只有一两秒但日积月累效率提升非常明显。history的!!表示上一条命令!$表示上一条命令的最后一个参数例如mkdir -p /data cd /data之后想直接再进入这个目录cd !$就能搞定不用重新打一遍路径。我个人的体会是Linux 命令学到最后拼的不是谁能背的选项多而是谁能在看到现象时第一时间想到正确的工具链并且不慌不忙地一层层排查下去。写命令笔记的意义也在于此不是为了收藏而是为了下一次遇到同类问题时能少花半小时试错。这篇作为系列的第十四篇内容偏重实战和坑点希望对正在这条路上往前走的人有些帮助。
返回列表