进程列表里状态为 Z 的条目涨到几百个,终止信号也没有反应,内存和磁盘都正常,只是可用进程号在不断减少。
原因不止一个,得分开看。父进程没有回收子进程的退出状态;父进程自己阻塞或者死循环,没机会处理信号;容器的一号进程不是初始化程序,不负责收割孤儿。
动手时先列出僵尸进程和它们的父进程
ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/'
然后确认父进程是谁在跑
ps -o pid,stat,cmd -p 父进程号
再往下重启父进程释放僵尸
systemctl restart app
末了容器启动时加上初始化进程
docker run --init myapp
中间停过一次,把已经改的东西回滚干净,再重新来一遍。
同样的操作我在测试机上先走了一遍,线上只做验证过的部分。
恢复的判定其实很直接。僵尸进程数量归零,进程号不再持续消耗,监控告警解除。
提醒一点。僵尸本身几乎不占内存,真正的问题是进程号被耗尽;临时清理只能重启父进程,根治还是要修代码。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。