加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.0472zz.com/)- 云渲染、网络安全、终端安全、数据治理、智能机器人!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

Unix调试总卡壳?9年运维揭5大隐性陷阱

发布时间:2026-10-15 08:15:40 所属栏目:Unix 来源:DaWei
导读:  去年十二月,凌晨三点十七分,IDC B2机房的空调啸叫忽然停了——不是坏了,是自动切换模式,声音从尖利变成低沉嗡鸣,像有人把耳朵按进变压器里。我蹲在 rackspace 缝里查一个卡死的 systemd service,手里捏着半凉的牛肉粉

  去年十二月,凌晨三点十七分,IDC B2机房的空调啸叫忽然停了——不是坏了,是自动切换模式,声音从尖利变成低沉嗡鸣,像有人把耳朵按进变压器里。我蹲在 rackspace 缝里查一个卡死的 systemd service,手里捏着半凉的牛肉粉丝汤外卖盒,汤底浮着三粒没化开的白胡椒,黏在盒壁上。王磊站我斜后方,嚼口香糖,咔哒、咔哒,每一声都比上一声慢半拍。他刚挂掉运维组的电话,左手无名指还在蹭手机屏边缘的油渍。


  第一个陷阱:你信 strace 信得太早。真出问题那天,我在容器里跑 strace -f -p 23987,看到三百七十二个 clone() 返回 -11(EAGAIN),当场就觉得是资源争用。我原以为是 cgroups 的 cpu.shares 配得紧,结果一通调,发现是宿主机 kernel 的 pid_max 被隔壁集群刷到了 1048576,而咱们那个破 init 容器硬生生启了八百多个子进程做健康检查——它自己根本没超限,只是 fork 环境太挤,fork 失败时连 errno 都没写进 stderr,只吞掉,静默退。strace 看到的 -11,根本不是 cgroup 拦的,是内核说“没 PID 号了,你等会儿”。这个我敢打包票。可到底是谁改的 pid_max?我说不准。监控告警日志里压根没这条变更记录,就像那天下雨,雨水从B2东侧吊顶接缝往下滴,在PDU箱顶积了薄薄一层,没人擦,也没人报——反正不短路,就不算故障。


  第二个陷阱:dmesg 不等于真相,它是被剪辑过的。你 tail -f /var/log/kern.log 看到 OOM killer 把 redis 干掉了,顺手就去调 memory.limit_in_bytes。错。那次我盯着 dmesg 刷屏看了四分钟,眼都酸了,突然发现第七行底下有一行被截断的 msg:“cgroup v2: …(truncated)”,再往上翻,发现同一秒有两条 log,一条是 oom_kill_task,另一条是“kmemleak: new object at ffff888a123b4000”。我翻完 kernel.org 的 kmemleak 默认行为文档才想起来——这个开关默认关着,我们编译内核时忘了打开 CONFIG_KMEMLEAK_AUTO_SCAN。它根本不会报警,只会悄悄漏。可这玩意儿跟 OOM 杀 redis 有关系吗?我说不准。我只知道那天李工一边调试一边啃煎饼果子,芝麻掉进键盘缝隙里,他用牙签抠了两下,又放弃,转头问我要不要尝一口。我没要。


  第三个陷阱:journalctl 纪录的是服务启动顺序,不是执行顺序。你看到 “containerd[1203]: task start failed” 就去查 containerd,傻。那次真正卡住的,是 init 容器里一个 /bin/sh -c 'while [ ! -f /tmp/ready ]; do sleep 1; done' ——它一直等,但 /tmp/ready 根本没被写入,因为那个负责写的 sidecar 进程,被 SELinux 的 type transition 规则拦在了 unconfined_t 上,init 容器的进程没权限写同一个 tmpfs mountpoint。journalctl 显示 sidecar “started successfully”,但它只是 execve 成功了,openat() 第一次就失败。log 里不报,因为它的错误处理里 catch 了 open 失败,然后 sleep 30 秒退出——日志就记了 “exited with code 0”,exit 0。我盯着那行日志看了十八秒,直到王磊把口香糖吐进空饮料罐,“哐当”一声,我才意识到不对劲。这个我敢打包票:exit 0 不代表运行成功,它只代表 shell 进程结束了。


  第四个陷阱:ps aux 的 TIME 列骗人。你看某个进程累计 CPU 时间两百小时,就以为它跑了两个月。不。它跑了十七次,每次五分钟,TIME 累加。我上次排查一个假死的 fluentd,看它 TIME 是 98:47:22,心说这老油条真能熬。结果一查 cgroup.procs,发现它 pid 每次重启都变,而 systemd 日志显示 “Started Fluentd (production)”,后面跟着 “Stop job for fluentd.service timed out after 90s”。哦,原来是它 shutdown 时挂死在 flush buffer,systemd 强杀重拉,log 全删了,TIME 继续累加。你信 ps,你就信了账本,不信流水。那个煎饼果子我最后还是尝了,太咸,酱放多了。李工笑笑,说“下次少放点”,没说下次啥时候。


  第五个陷阱:你以为你在调试 Unix,其实你是在调试人写的脚本。所有卡壳最后都收束到一行 sh 或 python 行为里——比如 os.path.exists() 在 overlayfs 上返回 false 却不报错;比如 awk ‘{print $NF}’ 碰到 tab 结尾字段直接切空;比如 docker run 的 --env-file 实际读取时忽略 # 开头但不忽略 # 后面带空格的注释行。这些不是 Unix 设计问题,是 Unix 工具链里那些被抄来抄去、没人维护的 wrapper script 搞的鬼。优胜劣汰?对。活下来的不是最稳的,是 bug 少到让甲方觉得“差不多”的那批。别的全淘汰了。我桌上那盒粉丝汤,最后剩了小半盒,汤面上的油凝成一块块半透明的膜,像极了某个容器镜像 layer 的 overlay 写时复制状态——看着完整,一碰就碎。


文章配图,仅供参考

  现在我把那台出问题的节点的 console log 导出来,放在 /tmp/debug-202312-b2-3am.log 里。谁要是感兴趣,可以看看第七千零四十一行。那里有个 timestamp 之后跟了三个空格,不是制表符,也不是一个空格。我不知道它怎么来的,但那个时刻,redis 恰好第一次没能连接上 Sentinel。要不要追?我不追了。明天交接给新来的实习生,让她先装个 tmux,别总 ctrl+c 崩掉 session——这比找 timestamp 空格重要。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!