我在 CentOS(主要是 6.4)上运行带有 prefork 和 mod_perl 的 apache 2.2.25。最近有一个实例特别混乱,分叉了子进程的子进程的子进程:
<snip>
\_ /usr/sbin/httpd
| \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| | | \_ /usr/sbin/httpd
| | | \_ /usr/sbin/httpd
| | | | \_ /usr/sbin/httpd
| | | \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| \_ /usr/sbin/httpd
| \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| | | \_ /usr/sbin/httpd
| | | | \_ /usr/sbin/httpd
| | | \_ /usr/sbin/httpd
| | \_ /usr/sbin/httpd
| \_ /usr/sbin/httpd
\_ /usr/sbin/httpd
| \_ /usr/sbin/httpd
\_ /usr/sbin/httpd
\_ /usr/sbin/httpd
</snip>
同时,盒子的内存也耗尽了(我不确定是先出现深度分叉还是先出现内存耗尽)。
我以前从未见过 Apache 这样做,而且还没有缩小原因范围。我正在调查的两种可能性是 mod_perl 中的内存泄漏(或者更确切地说,我们的代码中存在内存泄漏,由于 mod_perl 的存在而持续存在)或允许某些有限的 fork 炸弹的安全漏洞(无法 fork 任意子进程,但可以 fork 额外的 Apache 子进程)。
我不确定是什么原因导致 apache 像这样分叉(编辑我最初提到了关于 graceful 工作方式的错误观念,但我在这里的想法是,循环引用类型的内存泄漏(直接或间接地使用盒子上的所有可用内存)导致了某种 mod_perl 混乱,导致额外的工作子进程从子进程而不是主父进程分叉。我没有真正的理由这样做,只是试图调和这两个问题(深度分叉和内存使用)。
或者,我们可能存在一个我需要追踪的安全漏洞。
有人曾经见过 Apache 的这种行为并且知道解决方案吗?
答案1
事实证明,这是在 mod_perl 下的代码分叉(这已经是一个坏主意),然后由于不清理子进程而使情况变得更糟。在 mod_perl 下,当您分叉时,您不是在分叉代码,而是在分叉 apache。因此,该子进程继续像任何其他分叉的 apache 子进程一样提供内容,但不会被计入计数,因此如果您获得太多实例,它将永远不会被剔除。