Freeshell 7号节点3月27日凌晨 4:40 宕机。技术细节如下。

7号节点有个虚拟机在 vzctl chkpnt –suspend 时卡死了。vzctl 和虚拟机内的一个 nginx worker 进程处于 Running 状态并各占用一个 CPU,导致8个核中的2个基本上一直处于内核态(因为没有关抢占,其他进程偶尔还是能用它们的)。其中 nginx worker 在 schedule() 里死循环。这比之前发现的内核死锁问题更恶劣,因为占了 1/4 的 CPU 资源。虚拟机内其他进程都处于 uninterruptible sleep 状态,这是正常的,因为 suspend 就是让进程进入 D 状态。估计是 vzctl 先给其他正在运行的进程发中断,让这些进程切换到 D 状态,此时 nginx 进程正在执行 schedule(),在只有自己一个进程可调度的时候出现了 bug 进入死循环,vzctl 只好等待这个进程进入 D 状态。

因为其他节点也有类似情况,我希望查清原因,就启动了之前写的用 strace 监控所有进程系统调用的脚本。脚本里有 ps aux,由于挂死的 nginx worker 进程的 process virtual memory 已经被锁住,ps aux 就进入 uninterruptible sleep 了。内层脚本用的是 timeout 命令,因此卡死的 ps aux 不会阻塞主程序的运行。又由于脚本尝试监控所有进程,而不死的 ps aux 被当作是新进程了,又有新的 ps aux 去“处理”它,就陷入了死循环,越来越多的 ps aux 被创建,直到 PID 空间(1~32767)耗尽。

随后一段时间当然无法执行任何命令,过了一会儿可能是某些正常的进程退出了,空余出几个 PID,于是新进程可以创建了。但由于 PID 空间是接近满的状态,一些需要较多子进程的服务已经不能启动,虚拟机重启后部分系统服务(如 ssh)也不能初始化。在尝试解开被锁住的内核信号量无果之后,必须强制重启了。

这种情况下 init 6 是不行的,因为有卡死的虚拟机,而 init 6 过程中会关闭所有虚拟机,关机过程会卡在那个永远关不掉的虚拟机上。因此只能用 magic sysrq 了:


echo 1 | sudo tee /proc/sys/kernel/sysrq
echo b | sudo tee /proc/sysrq-trigger

执行之后终端立即卡住不动了,ping 也在这时停止响应,证明 sysrq 立即生效了。不过不知道是由于什么原因,过了20分钟,还没有重启起来,ping 不通。要等白天去机房看了。

非常抱歉此事对 freeshell 7号节点用户带来的影响。