人类的孤独像是一种与生俱来的残疾。

父进程为1的僵尸进程问题排查

Linux smallfish 4358℃

在开发服务端服务应用时,我们通常需要用到一种异常自启动的机制来做一些快速恢复尝试。这类服务一般是利用一个“守护进程”周期性地去检测另外一个进程的存活状态,如果不存活则把它重新拉起来。具体的实现可能有很多种,但本质还是一样。以我的一个项目为例,采用的是一个shell脚本开机自启动,然后周期性地扫描另一个服务进程是否有被拉起来。而另一个进程则只关注自身的服务,必要时(发生某种无法自行恢复的异常时)自行退出进程。

就是这么个简单的逻辑,稳定地运行了两年多,但是总会偶然的随机的在一些机器上出现服务中断,但没法自恢复的问题。这种无法自恢复的问题并不是机制本身引起的,因为发生异常时“reboot -f”也执行不了。这是更深层的问题,现在先不讨论这个。

发生无法自恢复异常的时候,我看到后台有一个奇怪的现象,即原来的服务进程变成了僵尸进程,而且其父进程为1,即init进程。这个现象跟我们平时想象得不一样。印象中好像父进程为1的进程不会成为僵尸进程,因为init进程会不断地去给这些孤儿进程“收尸”,然而为什么我们的服务进程虽然其父进程已经是init进程了还是会变成僵尸进程呢?

经过多处查找资料发现以下这些情况都有可能使父进程为1的进程成为僵尸进程:

1、多线程应用中,主线程已退出,但子线程还在执行;

2、进程还在被其他进程使用;

3、进程阻塞在某一IO请求上,这时控制权已经交到内核手上,这时如果子进程被kill,该进程就变成父进程为1的僵尸进程,直至IO请求被满足;

4、驱动异常,IO被阻塞(同第3点)。

因此,使用dmesg命令查看信息发现,服务进程使用到的一个外设驱动发生了异常,使得应用层的IO调用被阻塞,而检测线程检测应用逻辑出现异常后执行了“exit()”调用,因此服务进程成为了僵尸进程,而“守护进程”又没有对僵尸进程进行排除,导致它不会去启动新的应用进程来接续服务。不过此种情形下,即便重新拉起了新的服务进程仍然不能接续服务,因为此时出异常的是底层驱动,新的服务进程依然会被阻塞,然后再次成为僵尸进程。而且还会导致进程号资源被用完。所以,解决这个问题的根本是要去找到驱动出异常的原因。

转载请注明:OpenMind » 父进程为1的僵尸进程问题排查

喜欢 (10)