为什么我的mod_perl脚本会冻结我的服务器?

时间:2009-10-09 12:44:58

标签: linux perl apache virtualhost mod-perl

我不能让我的Perl脚本在服务器上运行稳定。 这是问题所在。

当脚本每秒访问次数超过5次时,服务器会冻结。 一段时间后,服务器永远挂起。 SSH没有响应,我必须重新启动服务器。

我正在使用Apache mod_perl

该脚本托管在Ubuntu下的Virtual Dedicated Server上。 我是通过SSH操作的。 这些是服务器参数 CPU:400 MHz RAM:256 MB

脚本的最长执行时间是200毫秒。

我已使用“top”实用程序监控服务器负载。 它不会显示任何问题,这是每秒加载5个脚本时的CPU统计信息:

Cpu(s): 12.1%us,  0.6%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si, 87.2%st

我可以使用哪些选项让脚本正常运行?

这是加载时ps aux | fgrep perl的结果:

ps aux | fgrep perl
www-data  2925  0.3  6.5  45520 17064 ?        R    17:00   0:01 /var/www/perl/loa -k start
www-data  2926  0.2  6.5  45520 17068 ?        R    17:00   0:01 /var/www/perl/loa -k start
www-data  2927  0.4  6.5  45676 17060 ?        R    17:00   0:01 /var/www/perl/loa -k start
www-data  2928  0.3  6.5  45676 17060 ?        R    17:00   0:01 /var/www/perl/loa -k start
www-data  2929  0.2  6.5  45676 17060 ?        R    17:00   0:01 /var/www/perl/loa -k start
www-data  2931  0.4  6.5  45740 17076 ?        R    17:00   0:01 /var/www/perl/loa -k start
root      2968  0.0  0.2   3196   656 pts/0    R+   17:06   0:00 fgrep perl

更新

我找到了瓶颈。 我一直在代码周围多次使用DateTime模块。 以下DateTime模块方法似乎非常慢。

  • 新()
  • 现在()
  • 集(...)
  • delta_ms(...)

我打算用快速类比替代它们。

另一个问题。 mod_perl实例需要大量内存。 我不明白为什么。 我试图运行一个不导入任何模块的简单perl脚本。 我在apache重启后运行它。 该脚本需要37M的内存。 为什么会这样? 你知道如何强制mod_perl不使用额外的内存吗?

一个没有mod_perl支持的常规perl脚本需要3-5M的内存。

伙计们,谢谢你们的帮助,我没想到会有这么好的回应!

更新2

我发现了另外一个事实。 我创建了一个简单的perl脚本,等待5秒钟。

#!/usr/bin/perl
use CGI;

my $query= new CGI;
my $content = "5 second delay...\n";

$query->header(
    '-Content-type' => "text/plain",
    '-Content-Length' => length($content)
);

print $content;

sleep(5);

然后我同时产生了许多这些脚本。 top工具中的隐藏时间(st)从0%上升到80%并保持高位,直到脚本完成。

这种负荷来自哪里?

另外,正如我已经提到的,每个perl实例需要36M的内存。

4 个答案:

答案 0 :(得分:5)

来自top的数字似乎表明您的VM外部的其他进程会限制您的CPU,请注意最后一个数字, 87.2%st ,这表示大约87%的CPU即使您的VM有想要运行的东西,您的虚拟机管理程序也会为VM外部的任务分配时间。这是否与您的问题有关很难说。

除了unwind所建议的升级服务器之外,使用zoul建议的持久进程环境,您的进程可能根本不受CPU限制,而是IO绑定,例如至于网络或磁盘访问,或内存限制。如果没有更多关于脚本在调用时实际执行的操作的细节,很难说。

编辑:您的内存使用情况信息的更新问题很明显,因为您的每个进程都需要45M的内存,并且共享17M以上。只运行5或6个进程,就超出了可用的RAM量。这是一个很好的内存供香草Perl脚本使用,它用它做什么?

答案 1 :(得分:3)

这不是一个非常大的服务器。它可以简单地产生让它跪下的Perl解释器吗?加载perl(我高兴地假设超过1 MB)每秒五次可能会要求太多。

当然,它应该被缓存,但在执行之前仍然需要初始化。

答案 2 :(得分:1)

虽然按照今天的标准,服务器的规格并不令人印象深刻,但我在类似的硬件上同时运行了相当复杂的东西。但是,我使用了非常准确的运行,只运行FreeBSD所需的配置。 (类似于使用ArchLinux可以实现的)。我怀疑你没有做很多自定义配置,并且接受了Ubuntu默认值,这些默认值对于那些规格来说可能太重了。

目前,我正在使用Linode 360​​,性能很好。

现在,所有这一切都是为了表明显而易见的:我们需要您没有与我们分享的信息。 Web服务器配置,脚本+解释器的内存占用,打开的文件数等等。要么尝试提供仍然存在问题的最小脚本,要么提供更多信息。

更新:现在我看到您正在使用mod_perl:1)您确定脚本所需的所有库都是在服务器启动时预加载的吗? 2)您是否在日志中收到任何variable won't stay shared条消息? 3)你读过mod_perl Performance吗? (Chapter 10: Sharing Memory可能特别相关)。

通常,您应该在Apache服务器的开头预加载公共库。作为一个非常简单的经验法则,共享的内容越多,您从服务器中获得的内容就越多。请参阅Startup File中的Practical mod_perl

另外,我认为每台服务器35MB有点多。如果你从Apache配置中删除了不需要的模块,我认为你可以减少这种情况。但是,即使你不能,也就是说35MB共享,​​加上最大子进程为50MB,你应该能够同时容纳大约20个客户端。

我刚注意到你正在测试的脚本。实际上,请尝试在服务器启动时预加载CGI,方法是在startup.pl添加以下行:

use strict;
use warnings;

use CGI();

其次,将该脚本更改为

#!/usr/bin/perl

use strict;
use warnings;
use CGI ();

$| = 1;

handle_request();

sub handle_request {
    my $cgi = CGI->new;

    my $content = "5 second delay...\n";

    print $cgi->header('text/plain'), $content;

    sleep(5);
}

请注意,您从未在原始脚本中发送标头(我也讨厌调用CGI实例$query,所以我也可以随意更改它。另请参阅Perl Reference

在此之后报告内存使用情况。

最后,你为什么要睡5秒? AFAIK,Apache默认的脚本超时时间为3秒。

答案 3 :(得分:0)

脚本使用什么样的界面?如果您可以避免一次又一次地运行perl可执行文件,例如使用FastCGI,您肯定会获得更好的性能。