如何避免在Apache 1.3下运行的Perl CGI脚本中的僵尸?

时间:2010-01-07 17:10:56

标签: perl apache zombie-process

各种Perl脚本(服务器端包含)在网站上调用具有许多功能的Perl模块。 修改 脚本使用使用lib 来引用文件夹中的库。 在繁忙时段,脚本(而不是库)变成了僵尸,并使服务器过载。

服务器列出:

319 ?        Z      0:00 [scriptname1.pl] <defunct>    
320 ?        Z      0:00 [scriptname2.pl] <defunct>    
321 ?        Z      0:00 [scriptname3.pl] <defunct>

我每个都有数百个实例。

修改 我们不使用fork,system或exec,除了SSI指令

<!--#exec cgi="/cgi-bin/scriptname.pl"-->

据我所知,在这种情况下,httpd本身将是该进程的所有者。 MaxRequestPerChild设置为0,不应让父进程在子进程完成之前死掉。

到目前为止,我们认为暂时暂停某些脚本有助于服务器应对已失效的进程并防止其崩溃,但僵尸进程仍然毫无疑问地形成。 显然 gbacon 似乎与他的理论最接近,即服务器无法应对负载。

什么可能导致httpd放弃这些进程? 是否有任何最佳做法可以防止这些情况发生?

由于

答案: 重点是Rob。 正如他所说,生成SSI的CGI脚本不会处理那些SSI。 SSI的评估发生在Apache 1.3请求周期中CGI的运行之前。这是通过Apache 2.0及更高版本修复的,因此CGI可以生成SSI命令。

由于我们在Apache 1.3上运行,因此对于每个页面视图,SSI都变成了不存在的进程。虽然服务器试图清除它们但是运行任务太忙而无法成功。结果,服务器崩溃了,变得没有响应。 作为一个短期解决方案,我们审查了所有SSI并将一些流程移至客户端以释放服务器资源并给予时间清理。 后来我们升级到Apache 2.2。

3 个答案:

答案 0 :(得分:7)

比最佳练习更多的创可贴,但有时你可以通过简单的

逃脱
$SIG{CHLD} = "IGNORE";

根据perlipc documentation

  

在大多数Unix平台上,CHLD(有时也称为CLD)信号对'IGNORE'的值有特殊行为。在这样的平台上将$SIG{CHLD}设置为'IGNORE'会导致当父进程无法wait()对其子进程进行创建时,不会创建僵尸进程( ie ,child进程自动获得)。在wait()设置为$SIG{CHLD}的情况下调用'IGNORE'通常会在此类平台上返回-1。

如果您关心子进程的退出状态,则需要通过调用waitwaitpid来收集它们(通常称为“收割”)。尽管这个名字令人毛骨悚然,但僵尸只是一个已退出的儿童过程,但其状态尚未获得。

如果你的Perl程序本身就是子进程变成了僵尸,那就意味着他们的父母(那些正在忘记你的代码的人)需要自己清理。一个过程不能阻止自己成为一个僵尸。

答案 1 :(得分:2)

我刚看到你的评论,你正在运行Apache 1.3,这可能与你的问题有关。

SSI可以运行CGI。但生成SSI的CGI脚本不会处理这些SSI。 SSI的评估发生在Apache 1.3请求周期中CGI的运行之前。这是通过Apache 2.0及更高版本修复的,因此CGI可以生成SSI命令。

正如我上面建议的那样,尝试自己运行脚本并查看输出。他们是否会产生SSI?

编辑:您是否尝试过启动一个简单的Perl CGI脚本来简单地打印出Hello World类型的HTTP响应?

然后,如果这样可以添加一些简单的SSI指令,例如

<!--#printenv -->

看看会发生什么。

编辑2:刚刚意识到可能发生的事情。当子进程退出并且没有收获时,僵尸就会发生。这些过程在处理表中闲置并慢慢耗尽资源。没有父级的进程是一个孤立的进程。

您是否在Perl脚本中分离进程?如果是这样,您是否已向父母添加了waitpid()调用?

你是否也在剧本中得到了正确的退出?

CORE::exit(0);

答案 2 :(得分:0)

由于你自己掌握了所有这些内容,我建议你从命令行一次运行一个单独的脚本,看看你是否可以发现那些悬挂的脚本。

ps列表是否显示一个特定脚本的实例数量过多?

您使用mod_perl运行CGI吗?

编辑:刚看到您对SSI的评论。不要忘记SSI指令可以自己运行Perl脚本。看看CGI正在试图运行什么?

他们是否依赖于另一台服务器或服务?