1. 从一次线上排查说起:命令不是背的,是组合用的
前阵子帮一个朋友处理服务器问题,他发来一张截图,load average 已经到了 8,后面跟着一句:“怎么办?”我回他:“先看看 top,哪个进程在最上面?”过了几分钟,他又发来一张 ps aux 的截图,说:“有十几个 Java 进程,我不知道该看哪个。”
那一刻我意识到,他的问题不是不会敲命令,而是不知道命令和命令之间怎么串起来。很多刚开始接触 Linux 的人都有这个阶段:ls、cd、ps、top 这些常用命令都会用,但真到了排查故障的时候,脑子是空的。这也是为什么我把这个系列写到第十三篇,决定换一种讲法——不再单独罗列命令,而是把高频命令放进真实场景里,讲它们的组合用法。
这篇内容主要面向两类人:刚入行的运维或后端开发,以及那些平时用 Linux 不多,但偶尔要上服务器查日志、看进程、测端口的测试和嵌入式工程师。我会从最典型的排障场景出发,把文件查找、进程分析、网络定位、权限检查、日志统计这些高频动作全部串起来。
读完你会发现,命令还是那些命令,但用的时候不再是“想到哪个敲哪个”,而是按一条链路走下来。学会这种链路思维,比多背二十个命令有用得多。先说一个我自己的习惯:接到任何 Linux 相关问题,我脑子里先蹦出来的不是具体命令,而是一张流程清单——资源层面有什么异常,进程层面是谁造成的,网络层面通不通,日志层面怎么说的。每张清单对应几条命令,排查起来就有条理了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件定位与内容检索:find、grep 的高频组合打法
找文件、找内容是 Linux 上最常做的事情。很多人习惯 cd 到目录里一层层 ls,或者打开一堆文件去翻,效率很低。实际上,文件定位这件事有两条路:按名字和属性找,用 find;按文件内容找,用 grep。两条路组合起来,几乎能解决所有“文件在哪儿”的问题。
2.1 find 不是简单的“按名字找”
find 的核心价值在于“按条件找”,而且条件可以叠加。文件大小、修改时间、属主、权限、目录深度都能作为筛选条件。举几个高频组合:
bash复制# 在 /var/log 下找 .log 结尾、超过 500MB、三天前修改过的文件
find /var/log -name "*.log" -type f -size +500M -mtime +3
# 在整个系统中找属于 www-data 用户的配置文件,避开权限报错输出
find / -name "*.conf" -user www-data 2>/dev/null
# 在当前目录往下最多两层,找 30 分钟内被修改过的文件
find . -maxdepth 2 -mmin -30
这里有几个容易踩坑的细节。
第一,-mtime +3 表示“超过 3 天前修改”,-mmin -30 表示“30 分钟内修改”。+ 和 - 的方向一定不能搞反,+3 是往过去数,-3 是 3 天以内。这个逻辑刚开始用很容易反,我建议你直接记一组对照:-mtime -1 是最近一天,-mtime +7 是一周以前的。
第二,find / 全盘扫描时,普通用户会遇到一堆 Permission denied 的提示,输出刷屏不说,还会干扰你判断。最后加 2>/dev/null 把错误输出丢进黑洞,是标准动作。这也是初学者最容易忽略的细节。
第三,find 拿到结果之后怎么处理?常见做法是配合 -exec 执行动作:
bash复制# 找到临时文件后删除,注意 {} 和 \; 的写法
find . -name "*.tmp" -type f -exec rm {} \;
如果你对批量删除不放心,可以先执行 -exec ls -lh {} \; 看看结果,确认没问题再换成删除命令。更保守的方案是用 -ok,它会在执行每条命令前询问一次,适合在生产环境操作。
我个人的习惯是,能用 find 的 -size、-mtime 缩小范围就绝不裸搜。搜索范围越小,命令跑得越快,误伤的概率也越低。
2.2 grep 帮你在内容里捞针
文件内容检索绕不开 grep。它的高频用法是递归搜索加过滤:
bash复制# 在 nginx 配置目录里递归搜 listen 关键字
grep -rn "listen" /etc/nginx/
# 只搜 .conf 文件,排除其他类型
grep -rn --include="*.conf" "listen" /etc/
# 拿进程列表过滤目标程序,同时排除 grep 自身
ps aux | grep "nginx" | grep -v grep
-r 递归目录,-n 显示行号,-i 忽略大小写,--include 限定文件类型。这些参数基本每次排查都会用到。
有一个经典笑话式的坑,就是 ps aux | grep nginx 的输出里总是带着一条 grep nginx 进程本身。这是因为 grep 匹配到的内容包含了正在执行 grep 的那个进程。很多人习惯追加 grep -v grep 把它过滤掉,但更干净的做法是直接用 pgrep -af nginx,专门就是干这个的,还能直接拿到 PID。不过管道写法在面试和老系统里太常见,还是建议懂。
除了过滤进程,grep 配合 -C(上下文行数)在日志排障里非常有效:
bash复制# 查看包含 ERROR 的行,以及前后各 2 行
grep -C 2 "ERROR" /var/log/app.log
# 只看前面 3 行
grep -B 3 "ERROR" /var/log/app.log
# 只看后面 5 行
grep -A 5 "ERROR" /var/log/app.log
日志里报错信息前后几行往往藏着真正的异常栈,只看匹配行会错失关键上下文。
2.3 实战:三步找到“占空间的老日志”
把上面两个命令合起来,处理一个真实需求:某台服务器磁盘告急,你想找出“三天前修改、体积超过 500MB、日志目录下的老文件”。
bash复制find /var/log -name "*.log" -type f -size +500M -mtime +3 -exec ls -lh {} \;
一条命令直接列清楚。如果你担心漏掉非 .log 后缀的滚动包,把 -name "*.log" 去掉,或者改成 -name "*.gz" 再跑一次,基本就覆盖全了。
但这里我要提醒一句:find 在 / 根目录下做全盘扫描是很慢的,生产环境慎用,最好把搜索范围限定在 /var、/home、/opt 这类实际存放业务数据的目录。定位大文件还有另一个组合思路:
bash复制# 用 du 扫目录大小,按人类可读格式排序,取前 10
du -ah /var 2>/dev/null | sort -rh | head -10
du -ah 列出每个文件的体积,sort -rh 按人类可读的大小数值逆序排序,head -10 取前十。这组命令在“不知道大文件在哪”的时候比 find -size 更直观,因为你能看到从大到小的全量清单。
3. 进程与系统资源排查:top、ps、free 的正确打开方式
服务器变慢,第一反应是看资源。但“看资源”不是盯着一个数字发呆,而是要知道每个数字背后对应哪个命令。我把这个章节拆成进程、内存、磁盘三块来讲。
3.1 ps aux 的输出到底怎么读
ps aux 和 ps -ef 是两派风格,前者 BSD 风格,后者 System V 风格,展示的字段略有不同,日常用哪个都行,我更习惯 ps aux:
bash复制ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
看输出时重点关注三块:%CPU 和 %MEM 决定资源占用,STAT 决定进程状态,COMMAND 决定这个进程是不是你认识的。
STAT 的字母含义是很多人容易忽略的考点:
| 状态 | 含义 | 难点 |
|---|---|---|
| R | running,正在运行 | 多个 R 状态说明 CPU 忙 |
| S | sleeping,可中断睡眠 | 大多数等待中的进程都是 S |
| D | 不可中断睡眠,通常等待 IO | D 状态多,磁盘或网络 IO 必有瓶颈 |
| Z | zombie,僵尸进程 | 无法直接 kill,要处理父进程 |
| T | stopped,被暂停 | 常见于 Ctrl+Z 停止的任务 |
如果你看到大量进程的 STAT 是 D,那说明系统在做密集的磁盘读写,CPU 再低也没用,根因在 IO。如果看到 Z,按我下面的顺序查:
bash复制# 找出所有僵尸进程的 PID 和父进程 PID
ps -ef | grep defunct
ps -o pid,ppid,stat,cmd -p <PID>
僵尸进程真正的工作是通过父进程回收的,直接 kill 僵尸进程没用。你要么处理它的父进程(如果父进程是 init/systemd 系,通常会自动回收),要么查清楚父进程为什么不去回收子进程状态。生产环境如果出现大量僵尸,常见的诱因是父进程代码里没有正确调 wait(),这就要反馈给开发了。
3.2 top 不只是进去按个 q
top 是最直观的实时监控入口,但很多人进去只看一眼 CPU 占用率就退了,属于端着金饭碗要饭。几个高频操作先记住:
top -c:显示完整命令行,而不是被截断的进程名top -H -p PID:看某个进程的所有线程,排查线程问题用- 进入 top 后按
P:按 CPU 排序;按M:按内存排序;按1:展开每个 CPU 核心的占用
至于 load average 那三个数,大概是整篇博文里被误解最深的指标。三个数分别代表 1 分钟、5 分钟、15 分钟的平均负载。很多人一看负载超过 CPU 核数就喊“过载”,其实更准确的理解是:这个数字包含了所有处于 R 状态和 D 状态的进程数量。如果你按 1 看到 4 个核心,load average 到 4 说明满负荷,超过 4 说明有任务在排队。但如果 CPU 占用率很低、负载却很高,那大概率是 D 状态进程在等 IO,这时候要用 iostat 看磁盘,或者检查是不是有 NFS 挂载在抽风。
内存排查看 free -h:
bash复制free -h
# total used free shared buff/cache available
# Mem: 3.7G 2.1G 250M 1.2G 1.4G 1.3G
注意最后一列 available 才是应用真正能拿到的内存。它包含了可回收的缓存,数值通常比 free 列大不少。很多人看到 free 很小就着急,其实 buff/cache 里大部分是文件缓存,系统内存紧张时会自动回收,不用慌。
3.3 磁盘满了却找不到大文件的怪事
df -h 看文件系统使用率,du -sh * 看目录大小,这两个命令用熟练之后会遇到一个经典问题:df 显示 / 已经 100%,但你在 / 下用 du -sh * 挨个扫,加起来的体积远小于 df 显示的已用空间。
这个问题的答案藏在一个很刁钻的场景里:某个进程打开了某个大文件,然后这个文件被删除(或者正在被写入但路径已经不存在了),但进程一直没退出,文件句柄还占着,磁盘空间自然不释放。你按照路径去找文件当然找不到。解决办法是:
bash复制# 找出所有已删除但还被进程占用的文件
lsof | grep deleted
找到对应的 PID 后,重启服务或者确认数据落盘后 kill 掉进程,磁盘空间就会瞬间释放。这个坑我踩过不止一次,每次都是“明明删了文件,磁盘还是满的”,实际上文件的“删除目录项”和“释放数据块”是两件事,只要句柄还开着,数据块就一直被标记为占用。
4. 网络与端口问题:ss、lsof、curl 的逐层定位链路
网络排障最大的痛点是“不知道问题出在哪一层”。你 ping 通了不代表端口通,端口通了不代表服务正常。这就像打电话:能打通是“信令通了”,接起来才有“服务正常”。所以排查顺序一定要从底层往上走:先看链路连通性,再看端口监听,再看应用返回。
4.1 ss 已经取代了 netstat
老系统管理员习惯用 netstat -tlnp,但 netstat 在某些新发行版里已经不预装了,它的替代品是 ss,更快、输出更全。高频用法:
bash复制# 列出所有 TCP 监听端口,显示进程名和 PID
ss -tlnp
# 查看当前所有 TCP 连接的汇总统计
ss -s
# 只看已建立的连接
ss -ant state established
-t 是 TCP,-l 是监听中的 socket,-n 让端口号显示为数字不要反解域名,-p 显示进程信息。这套参数组合基本是肌肉记忆,每次排查端口都要用到。
4.2 lsof 一步定位端口占用
用 ss -tlnp 看到端口和 PID 之后,如果你想反查“8080 端口被什么进程占了”,用 lsof -i:8080 更直接:
bash复制lsof -i:8080
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# java 1234 root 96u IPv6 12345 0t0 TCP *:8080 (LISTEN)
lsof 的输出会直接给出进程名、PID 和监听的地址。除了端口,它还能看进程打开了哪些文件,以及文件句柄数:
bash复制# 统计某个进程打开了多少文件
lsof -p 1234 | wc -l
如果这个数字异常大,很可能是文件句柄泄漏,再接上 lsof -p 1234 | head 看看到底是哪些文件被反复打开没关闭。
4.3 curl 是接口的“试纸”
接口调不通,怀疑是服务返回慢还是返回错?用 curl 把响应变成可读的指标:
bash复制# 只查看响应头
curl -I http://localhost:8080/
# 深入调试,显示建连、发送、响应全过程
curl -v http://localhost:8080/
# 忽略响应体,只输出状态码和耗时
curl -o /dev/null -s -w '状态码:%{http_code} 总耗时:%{time_total}s\n' http://localhost:8080/
第三条最实用。-o /dev/null 把响应体丢进黑洞,-s 静默不显示进度,-w 自定义输出。你能得到清晰的耗时数字,用来判断是连接慢、传输出问题还是服务本身处理慢。如果加上 -m 10 设置最长等待 10 秒,排查“接口卡死”类问题时就不会一直挂着。
请求体调试用:
bash复制curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://localhost:8080/api
4.4 一个端口连不上,完整的排查链路
假设你在机器 A 上访问机器 B 的 8080 端口不通,正确的顺序是:
bash复制# 第一步:网络层,ping 通说明主机可达
ping -c 4 <目标IP>
# 第二步:传输层,测试端口是否开放
telnet <目标IP> 8080
# 或者
nc -zv <目标IP> 8080
# 第三步:应用层,看 HTTP 服务是否正常返回
curl -v http://<目标IP>:8080/
每一步的结果对应不同的结论:ping 不通,先查路由、防火墙、云安全组;ping 通但 telnet 连不上,查端口是否监听、iptables/firewalld 是否放行;telnet 能通但 curl 异常,就是服务本身或应用配置的问题。
我在实际排查中还会加一个动作:回到服务器本地跑 curl -v http://localhost:8080/。如果本机正常、外部不通,问题大概率在网络策略或安全组;如果本机也不正常,那就是服务起失败了或者监听地址不对。这一步能快速把排查范围缩小一半。“先本机、后外部,先端口、后协议”是网络排障的基本功。
5. 用户、权限与安全基线:useradd、chmod、sudo 的细节
权限管理属于“平时不起眼、出事就背锅”的模块。测试环境怎么搞都行,生产环境一个权限配错可能就是安全事故。这一章我挑几个高频场景讲透。
5.1 新建用户不是 useradd 一下就行
很多教程会说 useradd username 就能建用户,但这样建出来的用户默认没有 home 目录、shell 可能还不是 bash,后面各种奇怪的问题都会冒出来。推荐的标准姿势:
bash复制# 创建用户并指定 home 目录和 shell
useradd -m -s /bin/bash -d /home/deploy deploy
# 设置密码
passwd deploy
# 把用户加入 wheel 组(RHEL/CentOS 系才有),或者 sudo 组(Ubuntu/Debian 系)
usermod -aG wheel deploy
# 验证用户和组信息
id deploy
-aG 里的 -a 很多人会漏掉。它的作用是“追加到附加组”,如果不加 -a,usermod -G wheel deploy 会把用户从其他附加组里全部移除,只保留 wheel。这个坑我见过有人直接把管理员账号的组配置冲掉了,导致用户丢失一堆权限。养成每次写 -aG 的习惯,能避免绝大多数组管理事故。
Ubuntu 系还有一个交互式命令 adduser,它会一步步提示你设置密码、填充信息,比 useradd 对新手友好得多。CentOS 系只有 useradd,没有交互提示,所以要习惯手动处理参数。
5.2 chmod 数字还是符号?分场景用
权限的表达方式有两种:数字和符号。数字法 750 每个人都会写,但它的本质是 r=4、w=2、x=1,三位数字分别对应属主、属组、其他人。例如 755 就是属主可读可写可执行,属组和其他人可读可执行。
符号法在针对性调整时更直观:
bash复制# 给脚本加可执行权限
chmod +x script.sh
# 去掉属组的写权限
chmod g-w config.txt
# 给属主加执行权限,同时设置属组和其他人为只读
chmod u+x,go=r file.txt
我通常的取舍是:初始化配置时用数字法一次性设好,临时调整用符号法,可读性强。比如给跑批脚本加执行权限,写 chmod +x run.sh 一眼就能看懂,写 chmod 755 run.sh 还得心算一遍。
需要注意 -R 递归参数。chmod -R 755 /data 会把目录下所有文件都设为 755,但如果里面有可执行脚本原本应该是 700,也会被动改掉。生产环境递归修改前一定先 find 看清楚目录结构。
chown 同理,改属主属组:
bash复制chown -R deploy:deploy /opt/app
属主和属组之间用冒号分隔。顺便说一句,/tmp 目录的权限是 1777,那个 1 是 sticky bit,表示只有文件属主和 root 能删除自己创建的文件,别手贱改成 777。
5.3 sudo 越授权越安全
给用户全部 sudo 权限是最省事的做法,也是最危险的做法。推荐用 visudo(注意不是直接编辑 /etc/sudoers,visudo 会做语法检查,配置错了还有挽救机会),给用户只授权必要的命令:
bash复制# 允许 deploy 用户免密执行 systemctl 管理指定服务
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx
NOPASSWD 表示执行时不用输密码,适合脚本自动化。但注意限定了命令的具体参数,就比 deploy ALL=(ALL) NOPASSWD: ALL 安全得多。可以用 sudo -l 查看当前用户有哪些 sudo 权限,这是巡检时的基本操作。
5.4 等保测评视角下的权限检查
在等保测评或安全巡检场景里,有几条命令几乎是固定动作:
bash复制# 检查是否存在 UID 为 0 的非 root 用户(UID 0 等于 root 权限)
awk -F: '$3==0{print $1}' /etc/passwd
# 检查是否存在空密码账号
awk -F: '($2==""){print $1}' /etc/shadow
# 查找所有带 setuid 位的程序(setuid 提权风险面)
find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null
这类检查不需要多复杂的工具,但很能体现基本功。看到 UID 0 的账号就去核实是不是有意的管理账号,看到空密码账号马上锁定处理,看到意外的 setuid 程序就要考虑移除执行权限或删除。安全基线和日常权限管理的核心思路是一样的:能不给的权限就不给,能限定范围的sudo就限定范围。
6. 日志里的真相:awk、sed、sort 组合分析
日志是 Linux 排障里最大的信息源。但日志文件动辄几百 MB,你不可能打开 nginx 的 access.log 用编辑器去翻。处理日志的正确姿势是用文本工具直接做统计和过滤。
6.1 tail -f 和 tail -F 的区别
跟踪日志是每天都要做的事。tail -f 是“跟踪文件”,tail -F 是“跟踪文件名”。看起来差不多,但遇到日志轮转就有大区别了。当 logrotate 把 app.log 改名为 app.log.1 并新建了 app.log 时,tail -f 会继续跟着旧的 app.log.1 那个文件句柄走,导致新日志不再输出;tail -F 则会检测到文件名变化,自动重新打开新文件。所以生产环境跟踪日志,我统一用:
bash复制tail -F -n 100 /var/log/nginx/access.log
-n 100 是先回看最后 100 行,再进入实时跟踪状态。排障时这个动作能让你快速看到“刚发生的事”。
6.2 awk、sed、sort 的分工认知
很多人把 awk、sed、grep 合称“三剑客”,但它们的定位完全不同:
- grep:按行过滤,擅长“找”
- sed:按行编辑,擅长“改”
- awk:按列处理 + 统计,擅长“算”
举几个最常用的场景。
awk 默认按空白字符分列,所以日志里的第一列通常是 IP,$9 在 nginx 默认格式里通常是状态码,$NF 是最后一列:
bash复制# 输出每一行的第一列(通常是 IP)
awk '{print $1}' access.log
# 统计日志中出现了多少次 500 状态码
awk '$9=="500"{count++} END{print "500次数:", count}' access.log
# 把最后一列(如果存放的是响应时间)求和
awk '{sum+=$NF} END{print "总耗时:", sum}' access.log
awk 的 BEGIN 块在读取文件前执行,END 块在读取完成后执行,非常适合做统计。上面第二条命令就是典型的 END 用法。
sed 做行替换、行区间提取很顺手:
bash复制# 查看日志第 100 到 200 行
sed -n '100,200p' app.log
# 把日志里的旧 IP 替换成新 IP,先备份再原地修改
sed -i.bak 's/192.168.1.10/10.0.0.10/g' app.log
-i.bak 会在原地修改前生成一个 .bak 备份文件,这个习惯强烈建议保留。直接 sed -i 不改名备份,一旦替换规则写错,几百 MB 的日志就废了。
sort 和 uniq 经常一起出现,因为 uniq -c 只能统计相邻的重复行,所以必须先用 sort 把相同的行聚到一起:
bash复制sort access.log | uniq -c | sort -nr | head -10
这条命令的含义是:排序 → 统计重复次数 → 按次数逆序 → 取前 10。它是“统计 Top N”的标准四段式。
6.3 访问日志分析三连
把上面的工具串起来,能直接解决几个高频的日志分析需求。
统计访问量最高的 10 个 IP:
bash复制awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10
查看状态码分布:
bash复制awk '{print $9}' access.log | sort | uniq -c
找到返回 500 错误最多的接口:
bash复制grep ' 500 ' access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -10
这三条命令覆盖了绝大多数“看日志找规律”的场景。很多人觉得 awk、sed 难,其实不要想着一次把所有功能学完,先把“按列提取、条件计数、排序统计”这三板斧练熟,就足够应付日常了。真正用多了,再慢慢补 substr、if、循环这些进阶能力。
7. 一个完整故障案例:从用户报障到定位根因的命令复盘
把所有命令串起来,走一遍完整排障流程。这次假设一个典型场景:网站访问变慢,用户已经开骂了。
7.1 第一步:确认是全局问题还是单点问题
上服务器第一件事,我不急着掏命令,先看整体状态:
bash复制uptime
# 13:22:01 up 30 days, 4:22, 1 user, load average: 12.87, 10.92, 8.53
看看 1 分钟、5 分钟、15 分钟负载的走势。负载从 8 涨到 12,说明问题正在恶化,不是偶发。接着用 ss -s 看一眼连接数有没有异常堆高:
bash复制ss -s
如果连接数暴涨,先怀疑流量异常或攻击;如果连接数正常,转向内部资源。
7.2 第二步:从进程、内存、磁盘三层找瓶颈
用 top -c 按 CPU 排序,看看到底是谁在消耗资源:
bash复制top -c
如果某个 Java 进程 CPU 占用一直在 200% 以上,记下 PID;然后用 top -H -p PID 看它的线程,再配合 jstack 定位到代码层。如果 top 里 CPU 不高、但 wa 列(IO 等待)很高,说明瓶颈在磁盘:
bash复制iostat -x 1
内存和磁盘检查并行做:
bash复制free -h
df -h
如果 free 的 available 已经见底,再看是不是有进程在疯狂吃内存:
bash复制ps aux --sort=-%mem | head -10
这条命令按内存占用从高到低排序,取前 10,比 top 里肉眼看更直观。
7.3 第三步:接口层确认到底是服务慢还是网络慢
用 curl 测试本地响应时间:
bash复制curl -o /dev/null -s -w '本地状态码:%{http_code} 耗时:%{time_total}s\n' http://localhost:8080/
如果本地返回只要 0.2 秒,用户却反馈很慢,问题大概率在网络链路或前端代理。如果本地也要 5 秒,问题就在应用层,直接去日志里捞证据:
bash复制tail -F -n 500 /var/log/app/error.log
再用 awk 统计最近日志里的错误码分布:
bash复制grep ' 500 ' /var/log/nginx/access.log | tail -1000 | awk '{print $7}' | sort | uniq -c | sort -nr | head -10
这样就能定位到是哪个接口大面积报 500,再结合 grep -C 5 查看异常栈,基本就到定位根因的一步了。
7.4 复盘:这套链路为什么通用
整个排查过程没有用到任何冷门命令,全是 uptime、top、ps、free、df、ss、curl、grep、awk 这些常用命令的组合。核心思路只有三条:
- 先看整体,再抠局部。负载高就先分清 CPU、IO、内存谁在瓶颈,不要乱猜。
- 先本机,后外部。curl 本机正常再查网络策略,能省下大量冤枉时间。
- 先确认现象,再翻日志。日志是证据链的终点,但不是起点,先要知道找什么。
最后再分享一个小习惯:我每次排查完问题,都会把敲过的命令、关键输出和结论存成一个 Markdown 文件,按日期归档。下次遇到类似问题翻出来,最快十分钟就能定位。这比记笔记有效得多,因为记录的是真实的排障流程,而不是孤立的命令。现在这套组合拳,就作为这个系列第十三篇的完整交付。
