
1. 这不是一份普通笔记而是一份Linux系统排障的“战地手记”你有没有过这样的经历凌晨两点生产服务器突然响应变慢top里看不到明显异常进程df -h显示磁盘还有30%余量但/var/log却写不进新日志或者某次内核升级后网卡驱动莫名失联ip link show里连eth0都不见了又或者一个看似简单的cron任务死活不执行日志里连影子都找不到。这些不是教科书里的标准错误它们没有明确的错误码没有清晰的报错路径它们是Linux世界里最让人抓狂的“疑难杂症”——症状模糊、线索断裂、复现困难、根因隐蔽。这份标题为“linux---疑难杂症总结笔记---1”的文档绝非随手记下的零散命令集合它本质上是一位在真实生产环境里摸爬滚打多年的系统工程师用血泪教训换来的“战地手记”。它记录的不是“如何安装Nginx”而是“当Nginx进程被OOM Killer悄无声息干掉后你该去哪里翻找那唯一的一行蛛丝马迹”它不讲“怎么配置SSH密钥”而是深挖“为什么密钥认证明明配置正确却在特定用户组下始终提示Permission denied (publickey)而sshd -T输出一切正常”。核心关键词——Linux、疑难杂症、系统排障、内核机制、日志分析、资源争用——已经点明了它的全部价值它是一把专为刺穿Linux系统表层平静、直抵底层幽暗逻辑的手术刀。这份笔记最适合三类人一是刚从实验室走向真实机房的运维新人他们需要避开那些前辈踩过的、文档里从不提及的深坑二是开发人员当你的应用在测试环境飞奔如风在生产环境却像被无形绳索捆住手脚时这份笔记能帮你快速判断问题究竟出在代码逻辑还是出在那个沉默寡言的Linux内核三是所有对“系统为何如此运行”抱有本能好奇的技术人它不提供标准答案但会教会你一套完整的、可复用的逆向推理方法论。它解决的不是某个具体报错而是“当一切看起来都正常但系统就是不按预期工作时我该从哪里开始怀疑”。2. 内容整体设计与思路拆解为什么是“笔记”而不是“教程”2.1 “笔记”体裁的底层逻辑对抗知识的熵增一份合格的“疑难杂症笔记”其结构设计本身就蕴含着深刻的排障哲学。它绝非按字母顺序排列的命令手册也不是按模块划分的理论教材。它的骨架是严格遵循一次真实故障的完整生命周期来构建的现象观察 → 初步隔离 → 深度挖掘 → 根因定位 → 验证修复 → 经验沉淀。这个顺序是无数次在压力下反复试错后凝结出的最优路径。比如笔记中关于“磁盘IO异常高但iostat无显著指标”的条目不会一上来就教你perf record -e block:block_rq_issue而是先引导你确认“高IO”是真实存在还是监控误报——这一步就过滤掉了至少30%的伪故障。这种设计是对抗技术知识天然“熵增”倾向的主动防御。在复杂系统中信息是碎片化的、噪声是海量的、因果是隐匿的。一份好的笔记其首要功能不是灌输知识而是为你搭建一个强大的“信息过滤器”和“逻辑校验场”。它强迫你在每一步操作前先问自己“我这一步的假设是什么这个命令的输出能证伪我的哪个假设如果结果不符合预期下一个最可能的排查方向在哪里”这正是“笔记”与“教程”的本质分野教程告诉你“世界应该怎样”而笔记则忠实地记录“世界实际怎样以及我们是如何一步步逼近真相的”。2.2 “疑难杂症”的界定标准超越man和--help这份笔记所收录的“疑难杂症”有一条非常硬核的筛选标准该问题无法通过查阅官方文档man、--help、kernel.org文档或主流搜索引擎的前两页结果直接获得确定性解决方案。它聚焦于那些“文档里没说但系统里确实会发生”的灰色地带。例如“systemd服务启动超时journalctl -u xxx只显示Failed with result timeout”这本身是一个标准错误但笔记会深入到systemd-analyze blame之后教你如何解读systemd-analyze plot生成的SVG图谱里那个耗时最长却未被标注的服务依赖项——这往往指向一个被systemd忽略的、由rc.local遗留下来的古老脚本。再比如“docker build过程中RUN apt-get update随机失败”标准答案是加--no-cache或换源但笔记会指出这很可能是overlay2存储驱动在特定内核版本下对/proc/sys/fs/inotify/max_user_watches的隐式依赖而这个参数的默认值在容器内会被继承导致apt的包索引更新过程因inotify句柄耗尽而静默失败。这种深度源于对Linux各子系统内核、C库、init系统、容器运行时之间耦合关系的长期观测。它不满足于“是什么”而是执着于“为什么偏偏是这里偏偏是现在”。2.3 “总结”的真正含义从个案到模式的升维“总结”二字在此语境下绝非对单个问题的简单复盘。它意味着将一次孤立的排障经历抽象、提炼为一个可迁移的“问题模式”Problem Pattern。每一个条目都包含一个标准化的“模式识别模板”。以“网络连接偶发性超时”为例笔记不会只记录“我那天重启了iptables就好了”而是会定义一个名为“状态跟踪表污染型超时”的模式其特征是netstat -s | grep -i retrans无异常ss -i显示重传队列为空但tcpdump抓包却能看到大量SYN重传其根因模式是conntrack模块的状态跟踪表/proc/sys/net/nf_conntrack_max被恶意扫描或配置不当的iptables规则如-m state --state INVALID -j DROP持续填充导致新连接无法建立其验证方法是conntrack -L | wc -l对比cat /proc/sys/net/nf_conntrack_count。这种模式化思维是资深工程师与新手的核心分水岭。它让你面对一个全新的、从未见过的报错时能迅速将其归类到已知的十几个“模式”中从而将一个未知问题降维成一个已知问题的变体极大缩短决策链路。这份笔记的价值正在于它为你预先构建好了这张覆盖Linux系统关键路径的“模式地图”。3. 核心细节解析与实操要点那些文档里不会写的“魔鬼细节”3.1 日志分析不止于journalctl更要读懂dmesg的“加密电报”绝大多数人认为journalctl是Linux日志的终极入口这是巨大的认知盲区。dmesg输出的内核环形缓冲区日志才是系统最底层、最原始的“心跳记录”它记录的是systemd甚至都来不及介入的瞬间。然而dmesg的输出常被形容为“加密电报”因为它充满了晦涩的内核符号和简略的缩写。笔记中对此有极其细致的破译指南。首先dmesg -T带人类可读时间戳是基础但远远不够。真正的关键在于dmesg -x显示消息级别和dmesg -L显示日志级别颜色这能让你一眼区分出KERN_ERR严重错误和KERN_INFO普通信息。更进一步笔记会教你如何利用dmesg | grep -E (oom|kill|segfault|panic)进行初步筛选但这只是开始。一个经典案例是“Out of memory: Kill process xxx (pid yyy) score zzz or sacrifice child”这条OOM Killer日志。新手看到score zzz就以为是随机选择而笔记会揭示其背后的残酷算法score并非随机数而是由badness()函数计算得出其核心公式为score (total_vm * 1000) / totalpages oom_score_adj。这意味着一个占用1GB虚拟内存但物理内存几乎为零的进程其score会远高于一个只占500MB但物理内存已满的进程。因此当你看到某个java进程被杀不要急着调大-Xmx先用pmap -x pid看它的RSS常驻集大小再用cat /proc/pid/status | grep -i oom确认其oom_score_adj值。这才是dmesg日志背后的真实故事。提示dmesg日志在系统重启后会被清空但/var/log/kern.log通常会持久化。笔记强调必须确保rsyslog或journald的ForwardToKernel选项为yes否则dmesg的精华部分将永远丢失。3.2 资源争用top的幻觉与cgroups的真相top是系统监控的瑞士军刀但它也是最大的幻觉制造者。笔记开篇就用一个震撼的案例打破这个幻觉一台8核CPU的服务器top显示%CPU总和稳定在790%load average却高达25。这显然矛盾——load average理论上不应长期远超CPU核心数。问题出在top的统计口径上。top的%CPU是基于/proc/[pid]/stat中的utime和stime字段计算的是进程在用户态和内核态消耗的CPU时间片占比。而load average反映的是处于RRunning或DUninterruptible Sleep状态的进程数量。当大量进程因等待磁盘IOD状态而阻塞时top的%CPU会很低但load average会飙升。笔记提供的实操要点是永远不要只看top必须配合iostat -x 1看%util和await和vmstat 1看r和b列。rrunnable列的数值才是load average的实时镜像。更深层的资源争用发生在cgroupsControl Groups层面。现代Linux发行版默认启用systemd的cgroup v2它将所有进程组织成一个树状结构。笔记会指导你使用systemd-cgls查看整个层级并用systemd-cgtop实时监控各slice的资源消耗。一个常见陷阱是docker容器默认运行在docker.slice下而systemd自身的system.slice可能因为systemd-journald的日志刷盘行为意外地占用了大量IO带宽。此时iotop可能只显示journald但systemd-cgtop会让你看到system.slice的整体IO压力。要解决它笔记会给出精确的systemctl set-property systemd-journald.service IOWeight10命令将journald的IO权重从默认的100降至10从而为业务容器让出资源。这种基于cgroups的精细化调控是top和htop永远无法触及的领域。3.3 网络栈调试ss比netstat快十倍tc是流量整形的终极武器当网络问题出现时netstat往往是第一个被祭出的工具。但笔记会毫不留情地指出netstat在现代Linux上已是“古董级”工具它依赖于遍历/proc/net/下的大量文件速度慢、精度低且在高并发连接场景下极易超时。取而代之的是sssocket statistics命令。ss -tuln-tTCP,-uUDP,-llistening,-nnumeric是netstat -tuln的完美替代其速度提升可达10倍以上因为它直接调用netlinksocket接口绕过了繁琐的/proc文件系统。然而ss只是起点。当问题深入到数据包层面时tctraffic control命令便成为不可或缺的利器。笔记中有一个极具代表性的条目“ping延迟忽高忽低mtr显示中间跳点稳定”。这通常不是网络设备问题而是本机TCP拥塞控制算法的锅。笔记会教你用ss -i查看单个连接的详细信息其中cwndcongestion window和ssthreshslow start threshold是关键。如果发现cwnd在极短时间内从数百KB骤降至几个KB那基本可以断定是cubic或bbr算法在探测到微小丢包后触发了激进的降窗。此时tc qdisc add dev eth0 root fq添加公平队列或echo net.ipv4.tcp_congestion_controlbbr /etc/sysctl.conf切换拥塞算法就是立竿见影的解决方案。tc的强大之处在于它不仅能诊断更能“治疗”。你可以用tc qdisc add dev eth0 root netem delay 100ms 10ms人为注入100ms的随机延迟来复现并验证应用在弱网下的表现这在测试环境中是无价之宝。4. 实操过程与核心环节实现一次完整的“磁盘空间消失”排障实战4.1 现象与初步隔离df与du的世纪之争让我们以一个经典的“磁盘空间消失”案例完整复现笔记中的实操流程。某天运维同学收到告警/var分区使用率已达98%。他立刻登录服务器执行df -h /var输出如下Filesystem Size Used Avail Use% Mounted on /dev/sda2 20G 19G 1.0G 95% /var他松了口气觉得还有1G可用不算紧急。但半小时后告警再次响起Use%变成了100%。他再次执行df -h /var这次Avail变成了0Use%是100%。他立刻执行du -sh /var/* | sort -hr | head -10想找出罪魁祸首结果令人震惊1.2G /var/log 800M /var/cache 500M /var/lib ... 总计约3.5Gdu统计的总和只有3.5G而df却说已用19G这就是著名的df与du不一致问题它是Linux系统中最能检验工程师功力的“试金石”之一。初步隔离的第一步是确认问题范围。笔记强调必须立即执行lsof L1 /var。这个命令会列出所有在/var分区上、已被删除unlinked但仍有进程打开着的文件。因为Linux的文件删除机制是“引用计数”只要还有进程持有该文件的文件描述符fd该文件占用的磁盘块就不会被真正释放df会继续将其计入已用空间而du则因其目录树已不存在完全无法统计到它。lsof L1 /var的输出往往就是真相COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME rsyslogd 1234 root 1w REG 253,2 18G 123456 /var/log/messages (deleted)看一个18G的messages日志文件被rsyslogd进程以wwrite模式打开着但它在文件系统中已经被rm命令删除了。df看到了这18G的磁盘块du却找不到它的“家”。4.2 深度挖掘/proc/[pid]/fd是你的取证现场找到嫌疑进程后下一步是深度挖掘确认其行为是否合理。笔记会指导你进入/proc/1234/fd/目录1234是rsyslogd的PID这是一个虚拟的文件系统里面全是该进程当前打开的所有文件描述符的符号链接。执行ls -la你会看到类似这样的输出lr-x------ 1 root root 64 Jun 10 10:00 0 - /dev/null l-wx------ 1 root root 64 Jun 10 10:00 1 - /var/log/messages (deleted) l-wx------ 1 root root 64 Jun 10 10:00 2 - /var/log/messages (deleted) ...fd 1和fd 2都指向同一个已删除的/var/log/messages文件。这解释了为什么df会将其计入。但问题来了rsyslogd为什么会一直持有这个已删除的文件这通常意味着日志轮转log rotation机制失效了。标准的logrotate配置会在轮转后向rsyslogd发送SIGHUP信号通知它关闭旧文件并打开新文件。如果logrotate没有成功发送信号或者rsyslogd没有正确处理该信号就会导致这种“僵尸文件”堆积。此时笔记会教你一个关键验证步骤检查rsyslogd的配置文件/etc/rsyslog.conf查找$ActionFileDefaultTemplate和$ActionFileEnableSync等指令并重点检查logrotate的配置/etc/logrotate.d/rsyslog。一个常见的错误配置是postrotate脚本中缺少invoke-rc.d rsyslog rotate /dev/null或等效的systemctl kill --signalSIGHUP rsyslog.service命令。这便是根因所在自动化流程的某个环节出现了“静默失败”。4.3 根因定位与验证修复重启不是万能药kill -USR1才是正解找到根因后修复方案就呼之欲出了。最粗暴的方式是systemctl restart rsyslog但这会导致日志服务短暂中断对于生产环境是不可接受的。笔记推崇的优雅方案是向rsyslogd进程发送USR1信号。man rsyslogd中明确写道“USR1signal causes rsyslogd to close all open files and re-open them. This is useful for log rotation.” 这正是我们需要的执行kill -USR1 12341234是rsyslogd的PID后rsyslogd会立即关闭所有fd然后根据配置重新打开新的日志文件。此时再执行lsof L1 /var那个18G的(deleted)文件将彻底消失。df -h /var的输出会立刻刷新Avail空间将恢复。为了验证修复效果笔记建议执行一个“压力测试”手动触发一次logrotate -f /etc/logrotate.d/rsyslog然后再次检查lsof L1 /var确认没有新的(deleted)文件产生。这一步是将一次被动的救火转化为主动的、可验证的流程加固。注意kill -USR1是rsyslogd的特有信号。其他日志服务如syslog-ng使用的是HUP信号。务必查阅对应服务的man手册切勿张冠李戴。5. 常见问题与排查技巧实录那些年我们一起踩过的坑5.1 “No space left on device”但df显示空间充足检查inode耗尽这是新手最容易栽跟头的“第一课”。df -h显示/home还有50%的空间但当你尝试touch test.txt时却得到冰冷的No space left on device。此时df -i显示inode使用情况是唯一的救命稻草。df -i /home的输出可能如下Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sdb1 1000K 1000K 0 100% /homeIUse%为100%这意味着虽然磁盘块还有富余但用于存储文件元数据metadata的inode节点已经全部用光。这通常发生在大量创建小文件的场景比如Web服务器的临时缓存、Git仓库的.git/objects目录、或者某个程序的bug导致无限循环创建空文件。解决方法很简单find /home -xdev -type f | head -10000 | xargs rm -f谨慎使用先head预览或者更安全地find /home -xdev -type f -size 0c -delete删除所有0字节文件。预防胜于治疗笔记会建议在创建新文件系统时使用mkfs.ext4 -i 4096 /dev/sdb1将每个inode分配的字节数从默认的16384减小到4096从而在相同磁盘容量下创建更多的inode。5.2systemctl start xxx失败journalctl里却一片空白检查unit文件语法systemctl start nginx返回Job for nginx.service failed但journalctl -u nginx却没有任何输出。这往往意味着systemd在加载nginx.service单元文件时就因语法错误而直接放弃了它根本没走到启动进程那一步。此时systemctl daemon-reload和systemctl status nginx是无效的。正确的做法是使用systemd-analyze verify /usr/lib/systemd/system/nginx.service或你的自定义unit文件路径。这个命令会像编译器一样对unit文件进行静态语法检查并报告出精确的行号和错误类型比如Unknown section Service2或Missing in assignment。笔记强调systemd的unit文件语法极其严格一个多余的空格、一个拼错的单词都会导致整个服务无法加载。养成每次修改unit文件后必先systemd-analyze verify的习惯能避免90%的此类“静默失败”。5.3ssh连接缓慢ssh -v显示卡在debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password禁用GSSAPI这是一个流传甚广的“慢SSH”问题。ssh -v的详细日志显示客户端在完成密钥交换后会尝试与服务器进行GSSAPIGeneric Security Services Application Program Interface协商这个过程在网络不佳或服务器GSSAPI配置异常时会耗费长达10-30秒的超时等待。解决方案极其简单在客户端的~/.ssh/config文件中为对应的主机添加一行Host your-server.com GSSAPIAuthentication no或者在连接时直接使用ssh -o GSSAPIAuthenticationno useryour-server.com。笔记指出GSSAPI主要用于企业级的Kerberos单点登录对于绝大多数个人和中小企业的SSH使用场景它完全是冗余且有害的。禁用它是提升SSH体验最立竿见影的优化之一。5.4docker run报错OCI runtime create failed: unable to retrieve OCI runtime error检查cgroup版本兼容性在较新的Linux发行版如Ubuntu 22.04上systemd默认启用cgroup v2而一些老旧的Docker版本如19.03之前的版本仅支持cgroup v1。当两者不兼容时就会出现这个晦涩的OCI错误。验证方法是cat /proc/1/cgroup如果第一行是0::/则表示cgroup v2已启用。解决方案有两个一是升级Docker到20.10或更高版本它原生支持cgroup v2二是在/etc/default/grub中将GRUB_CMDLINE_LINUX行修改为GRUB_CMDLINE_LINUXsystemd.unified_cgroup_hierarchy0然后sudo update-grub sudo reboot强制系统回退到cgroup v1。笔记强烈推荐第一种方案因为cgroup v2在资源隔离和性能上具有压倒性优势回退是一种妥协而非长久之计。6. 经验心得与避坑指南一位老炮儿的肺腑之言6.1 “先做减法再做加法”排障的黄金法则这是我从业十年踩过无数坑后总结出的最朴素、也最有效的排障心法。当一个系统出现异常时人的第一反应往往是“加点什么”加一个监控加一个日志加一个补丁加一个配置。但绝大多数疑难杂症其根源恰恰在于“加得太多”。一个典型的例子是某次线上服务响应变慢团队先后加了Prometheus监控、ELK日志收集、Jaeger分布式追踪最后发现罪魁祸首是Prometheus的node_exporter在采集/proc下某些特殊文件时引发了内核的锁竞争。问题的解决不是给node_exporter加更多参数而是直接将其--collector.filesystem.ignored-mount-points参数设置为忽略/proc和/sys做了一次精准的“减法”。笔记中所有条目的开头几乎都有一句“请先尝试关闭XXX服务/卸载XXX模块/注释掉XXX配置”这并非懒惰而是对系统复杂性最深刻的敬畏。在动手之前先问自己“这个新增的东西有没有可能是问题的诱因”6.2 “信任但要验证”对一切输出保持健康的怀疑Linux世界里没有绝对的权威。man页面可能过时--help输出可能有歧义journalctl的日志可能被rate-limit截断top的%CPU可能因采样周期而失真。笔记中反复强调的一个习惯是永远不要只相信一个命令的输出要用多个独立的命令去交叉验证。比如你想确认一个端口是否真的被监听不要只信netstat -tuln | grep :8080还要同时执行ss -tuln | grep :8080和lsof -i :8080。如果三个命令结果一致那可信度就很高如果netstat显示有而ss和lsof都显示无那基本可以断定是netstat的缓存或权限问题。这种“三角验证”法是避免被单一工具的Bug或局限性带入歧途的最可靠保障。它培养的是一种工程师的“批判性思维”而这恰恰是所有自动化工具都无法替代的核心能力。6.3 “记录即思考”为什么手写笔记比电子笔记更有效最后我想分享一个可能反直觉的观点在排障的最关键时刻我依然坚持用纸质笔记本手写关键信息。不是因为怀旧而是因为手写这个动作本身就是一个强制的、深度的思考过程。当你在纸上写下dmesg | grep -i error的输出时你的大脑会不自觉地对每一行进行初步的语义解析和归类当你画出systemd服务依赖图时你必须理解Wants、Requires、BindsTo之间的微妙差别。而电子笔记尤其是复制粘贴会极大地削弱这个思考过程。笔记中那些最精华的“模式识别”条目几乎都诞生于这样一张张写满潦草字迹和箭头的A4纸上。所以我的建议是把你的电子笔记当作最终的知识结晶而把你的纸质笔记本当作每一次排障战役的“作战沙盘”。它不追求美观只追求在那一刻你的大脑与系统最真实的脉搏同频共振。