7

各种 Perl 脚本(服务器端包含)正在调用网站上具有许多功能的 Perl 模块。 编辑: 脚本使用use 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。

4

3 回答 3

7

比最佳实践更多的创可贴,但有时你可以摆脱简单

$SIG{CHLD} = "IGNORE";

根据perlipc 文档

在大多数 Unix 平台上,CHLD(有时也称为CLD)信号对于'IGNORE'. 在这样的平台上设置$SIG{CHLD}为当父进程在其子进程上失败时不会创建僵尸进程(,自动收割子进程)。在此类平台上,使用set调用通常会返回 -1。'IGNORE'wait()wait()$SIG{CHLD}'IGNORE'

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

如果您的 Perl 程序本身就是成为僵尸的子进程,这意味着它们的父进程(那些分叉并忘记您的代码的进程)需要自己清理。进程无法阻止自己变成僵尸。

于 2010-01-07T17:14:34.607 回答
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);
于 2010-01-07T21:25:57.047 回答
0

由于您自己拥有所有这些位,我建议您从命令行一次运行一个单独的脚本,看看您是否可以发现那些挂起的脚本。

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

您是否使用 mod_perl 运行 CGI?

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

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

于 2010-01-07T18:25:31.467 回答