我们的服务A会对服务B进行管理操作,A服务定期去管理中心(下文简称为CC:Control Center)下载相关信息,然后在本机上进行多个B服务进程的后台启动或者kill以及检测B服务进程是否异常终止并进行拉起等操作。周四的时候,因为异常报警信息,登陆线上机器才发现该机器上部分B服务进程成为了僵尸进程。如下图所示:
图-1 部分进程成为了僵尸进程
我们可以发现进程PID为29329、29340、29351、29362等五个进程成为了僵尸进程。
一、僵尸进程
“简单讲,当Linux上的一个进程(process)死亡的时候,它并没有直接从内存中完全移除——它的进程描述符(进程PID)依然存在于内存中(PID仅仅占用很少的内存空间)。进程的状态变为EXIT_ZOMBIE,并且该进程的父进程会被发送SIGCHLD信号来通知它的子进程已经死亡了。然后父进程应当执行wait()或者waitpid()系统调用来读取死亡进程的退出状态和其它信息。这将允许父进程获取死亡子进程的相关信息,当 wait() 或者 waitpid() 调用成功之后,僵尸进程将会被从内存中彻底移除。
通常这发生的非常迅速,因此你将看不到僵尸进程在系统中不断堆积。然而,如果父进程未能进行正确地编程处理或者永远没调用wait()或者waitpid(),它的僵尸子进程会一直驻留在内存中直到它们被清理掉。”
值得注意的是,对于僵尸进程,使用 kill -9 PID 是无法杀死它的。可以使用的方法之一为发送 SIGCHLD信号给父进程,这个信号告诉父进程去执行wait()或者waitpid()调用,清理它的僵尸子进程。但是如果父进程如果未能合适地处理或者忽略了SIGCHLD信号,这将不起作用。
另外一种方法是直接kill掉或者关闭僵尸子进程的父进程。当创建僵尸子进程的进程结束时,init进程将成为这些僵尸进程的父进程。init进程会周期性地执行wait()系统调用来清理僵尸子进程,因此init将迅速干掉僵尸进程。