前言
有一天,发现自己的 All in boom All in one 云服务器时不时在登录的时候提示由很多僵死进程(如下图所示),就觉得很奇怪。
这东西虽然吧,截至目前暂时没有引发什么服务停止运作;但是吧,看着总是慌慌的,存在一定的隐患,让人有一种”你现在不能休息,周围有怪物在游荡“的感觉。所以,觉得还是尽量避免出现僵死进程比较好,于是就进行了排查。
什么是僵死进程
僵死进程(defunct),又叫孤儿进程(orphan process)。
当fork一个新进程的时候,子进程一般会和父进程同时运行。当子进程结束的时候,它与父进程的关联还会保持,直到父进程也正常终止或者wait,子进程才结束。因此,进程中代表子进程的表项不会立即释放。虽然子进程已经不能正常运行,但是它仍然存在于系统之中,因为它的退出码还要保存起来,以备父进程今后的wait调用使用。
这种情况我们称已经结束了但是还不能释放的子进程为僵死进程。僵死进程不能用kill -9杀死(本来都是死的了,怎么再死)。
虽然僵进程已经是死的了,但是它在进程表(processs table)中仍占了一个位置(slot)。僵死进程会占用系统资源,如果系统有太多的僵死进程,当PID耗尽的时候,可能出现不能再启动其他进程,甚至导致系统崩溃。所以要尽量避免僵死进程的产生。
问题定位
1. 先找到是哪些僵死进程
ps aux | grep "Z"
输出:
一堆[git]进程,孤儿进程,找找他爹是谁,竟然无情的抛下他的孩子们。
2. 找父进程
抓一个孤儿进程过来,问问他爹是谁,就抓pid
为 873128 的这个吧,如下命令:
ps -ef | grep 873128
pid有两列,左边这列是进程的pid,右边这列是父进程的pid,找到他的父进程pid为1909。
3. 继续溯源:
ps -ef | grep 1909
找到一个名为node
的进程,这个进程就是元凶了,产生了好多孤儿进程。
但为了更加进一步的找到问题的根本,不能把这个进程杀掉草草了事,得查明元凶背后的主使。继续溯源:
ps -ef | grep 1555
找到是一个docker容器跑的进程。我的机器上跑着很多docker
容器,要查一查到底是哪个容器搞的鬼。
docker ps
根据上面的进程信息,可以确定是这个名为jd的容器搞的鬼。
问题解决
查询之后,发现是因为这个容器用node.js
作为初始化进程导致的。node.js官方也提到,不建议在docker中作为PID 1来启动。(原文连接)
解决办法是,在启动容器的时候,加上--init
参数,这样可以用docker的init进程作为初始化进程。希望这样,能让docker的init照管好这些”孤儿“们。
docker stop jd
docker container rm jd
docker run -itd --init --name jd \
> --restart always \
> -v jd_base:/jd \
> -e ENABLE_HANGUP=true \
> -e ENABLE_WEB_PANEL=true \
> --network host \
> shuye72/jd-base:gitee
总结
找到僵死进程。
找到父进程。
找到父进程的问题根源。
docker中以node.js为初始化进程所致。
关闭并删除容器,加上--init参数来重新启动容器。