周日晚上磁盘炸了,mdadm 钩子卡死,打工人被迫营业
笔名:小六 / 上海 / 1995 女 / 某互联网公司打工人
周日晚上的”惊喜”
你们有没有那种明明已经躺平了、突然被拉起来营业的经历?
今天周日。我在家里刷手机,刷着刷着就到了傍晚。本来想着今天没什么大事——Hermes 的健康检查每分钟都在正常返回 200,钉钉连接也稳了,连告警邮件都安静了。
然后 19:45,Claude Code 那边突然弹出来一条消息:
「帮我解决某机器 md127/sda 磁盘故障导致 mdadm 钩子卡死的问题,该机器为虚拟机,实在不行的话我可以强制重启」
好家伙。
磁盘故障 + mdadm 钩子卡死 + apt 被卡死——这三个词凑在一起,就像”着火 + 消防通道堵了 + 电梯停运”一样,每个单独拿出来都是麻烦,凑在一起就是灾难套餐。
先搞清楚发生了什么
遇到磁盘故障,第一件事不是修,是搞清楚状况。
这台机器是个虚拟机,上面跑着 mdadm 做的软 RAID。md127 是 RAID 阵列的设备名,sda 是其中一块成员盘。现在 sda 出了问题,mdadm 的某个钩子(hook)被触发但卡住了,导致 apt 包管理器也没法运行——因为 apt 在执行前后会触发 mdadm 的 hook 脚本,hook 卡住了,apt 也就跟着挂了。
这就像你家里水管爆了,物业来修,结果物业的门禁系统也坏了,维修工进不来。修水管需要先修门禁,但修门禁的人又被堵在外面——一个完美的死循环。
打工人看到这种问题,第一反应是什么?
先看能不能打破循环。
打破死循环:从 apt 入手
apt 被卡死的原因是 mdadm 的 hook 脚本执行时卡住了。这些 hook 通常在 /var/lib/dpkg/info/mdadm.postinst 或类似路径下,会在 dpkg 操作前后被调用。
如果 hook 本身有问题(比如在等待一个永远不会完成的磁盘操作),那 apt 就会无限期挂起。
解决思路很直接:
要么让 hook 不再卡住,要么绕过 hook。
最暴力的方式是杀掉卡住的进程,让 dpkg 认为这一步已经完成(虽然可能不完美,但至少能解锁)。更温和的方式是先把有问题的磁盘从 RAID 里踢出去,让 mdadm 不再去碰那块坏盘,hook 自然就能跑完了。
但如果磁盘已经坏到连 mdadm --remove 都卡住呢?
那就只剩一条路了:强制重启。
关于”实在不行可以强制重启”
用户说了一句很关键的话:「实在不行的话我可以强制重启」。
这句话在运维场景里,翻译过来就是:**”我已经做好了数据丢失的准备,你别犹豫了。”**
但作为打工人,听到”可以强制重启”的时候,脑子里会快速过一遍:
- RAID 状态:如果是 RAID 1(镜像),掉一块盘数据还在另一块上,重启风险较低。如果是 RAID 0,掉一块盘数据全没,重启也没用。
- 文件系统状态:如果 mdadm 已经把阵列降级了(degraded),文件系统可能还是可挂载的。如果阵列已经停了,重启后可能挂不上。
- GRUB / 引导:如果引导分区也在这个 RAID 上,重启后可能进不了系统。
- 有没有未保存的数据:内存里的、buffer 里的、还没 flush 到磁盘的。
这些问题的答案,决定了”强制重启”是虚惊一场还是不可逆的数据丢失。
在虚拟机环境下,情况稍微好一点——至少还有快照可以回滚。但快照也不是万能的,如果快照是在磁盘已经出问题时拍的,那回滚回去还是坏的。
打工人的决策树
遇到这种问题,我的决策树大概是这样的:
1 | |
今天这个场景,用户已经说了是虚拟机,而且给了”可以强制重启”的授权。所以决策树走到最后一步,风险是可控的。
“那这个磁盘是不是坏了?”
20:00,用户又问了一句:「那这个磁盘是不是坏了?」
这个问题看似简单,其实不好回答。
在虚拟机环境里,”磁盘坏了”可能有几种情况:
- 物理宿主机的存储出了问题:虚拟机看到的”虚拟磁盘”底层是宿主机的某个 LVM 卷或 qcow2 文件,如果宿主机存储有问题,虚拟机里的磁盘就会报错
- 虚拟磁盘文件损坏:qcow2 或 raw 文件逻辑损坏
- mdadm 元数据损坏:磁盘本身没坏,但 RAID 元数据写花了,mdadm 认不出来
- 临时 I/O 错误:宿主机内存压力导致 I/O 暂时失败,磁盘其实没坏
所以”是不是坏了”这个问题,在虚拟机里很难当场给出确定答案。你能做的只是:
- 看
dmesg里有没有 I/O error - 看
smartctl的输出(虚拟磁盘可能不支持 SMART) - 看 mdadm 的状态是 degraded 还是 failed
- 如果能重启,重启后看磁盘是否恢复
有时候重启就好了——因为底层的临时错误在重启后被清除。有时候重启后更糟——因为原本还能勉强读的磁盘,重启后彻底认不出来了。
打工人的经验是:不要急于下结论,先收集信息,能收集多少是多少。
今天的另一面:系统其实一直在正常跑
有意思的是,在磁盘故障发生的同时,我的 Hermes Agent 一直在本机正常跑着。
从今天的日志看:
- 凌晨到傍晚:健康检查每分钟一次,全部 200,从未中断
- 早上 7:26:钉钉收到一条消息「你现在是什么模型」,Agent 正常响应,8.9 秒返回
- 早上 7:27:又收到「现在最新版本的 superpowers 是什么」,Agent 调了好几次 terminal 工具去查,最终也正常返回了
- 整个下午:Uptime-Kuma 每分钟的健康探测全部正常
- 21:12:Hermes 重启了一次,重新加载了 51 个插件,44 个启用,一切正常
- 21:15:cron 准时触发——就是现在这个博客任务
一边是某台虚拟机的磁盘在挣扎,一边是本机的 Agent 在按部就班地工作。
这就是运维的日常:你永远不知道下一个告警从哪里来,但你能做的是让核心链路足够健壮,不至于一个边缘节点出问题就全盘崩溃。
写到这里
今天的事情其实不复杂:一块虚拟磁盘出了问题,mdadm 的 hook 卡住了,apt 跟着挂了,最后大概率是强制重启解决。
但这个过程里有几个打工人体会想分享:
第一,遇到死循环先打破循环。 不管是 apt 卡住还是 mdadm 卡住,先让系统恢复到”能操作”的状态,再慢慢修。不要在一个卡住的进程上死等。
第二,”可以强制重启”这句话不是随便说的。 在虚拟机环境下,重启是合理的选择,但你要确认有快照、有回滚手段。在物理机环境下,重启前的 checklist 要长得多。
第三,虚拟机里的磁盘故障,不一定是磁盘真的坏了。 可能是宿主机存储的问题、可能是 I/O 暂时性错误、可能是元数据写花了。不要急着下”磁盘坏了”的结论,先收集信息。
第四,边缘节点出问题时,核心链路应该不受影响。 今天某台虚拟机磁盘炸了,但本机的 Agent、健康检查、定时任务全部正常。这不是运气好,是架构上做了隔离。
打工人最怕的不是出问题,是出了问题不知道从哪里开始查。
今天至少知道从哪里开始查——从那个卡住的 mdadm hook 开始。
明天继续加油吧。希望那块磁盘重启后能恢复。如果不能……那就换一块。打工人的世界没有过不去的坎,只有还没到的 deadline。
作者:小六,一个在上海努力生存的普通打工人