Apache2 为什么apache mod_perl进程会变成僵尸?

Apache2 为什么apache mod_perl进程会变成僵尸?,apache2,mod-perl,Apache2,Mod Perl,有时,mod_perl apache进程在“top”实用程序中被标记为“defunct”,即成为一个僵尸进程。 这是正确的行为吗? 我一定要担心吗 我们的Perl脚本非常简单,它不会产生任何子进程。 僵尸程序很快就消失了。 Apache2,Ubuntu 我们的apache配置如下: 这是顶部的快照 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 19525 www-data 20 0 55972

有时,mod_perl apache进程在“top”实用程序中被标记为“defunct”,即成为一个僵尸进程。 这是正确的行为吗? 我一定要担心吗

我们的Perl脚本非常简单,它不会产生任何子进程。 僵尸程序很快就消失了。 Apache2,Ubuntu

我们的apache配置如下:

这是顶部的快照

    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
19525 www-data  20   0 55972  25m 4684 S 10.3  2.4   0:00.32 apache2
19486 www-data  20   0 52792  21m 4120 S  1.7  2.1   0:00.05 apache2
19538 www-data  20   0 52792  21m 4120 S  1.3  2.1   0:00.04 apache2
19539 www-data  20   0     0    0    0 Z  0.7  0.0   0:00.03 apache2 <defunct>
19481 www-data  20   0 52860  21m 4016 S  0.3  2.1   0:00.05 apache2
19521 www-data  20   0 52804  21m 3824 S  0.3  2.1   0:00.08 apache2

我的第一个怀疑是,你真的在分岔,但也许你没有意识到。是否可以包含您的代码?请记住,任何
系统
或``调用都是分叉的。这很容易在CPAN模块内部发生,而您没有意识到。有一些关于mod_perl和forking的有用信息(包括如何创建僵尸以及如何避免僵尸)

更新:尝试将其添加到配置中:

# Monitor apache server status
ExtendedStatus On
<VirtualHost 127.0.0.1:80>
    <Location /server-status>
        SetHandler server-status
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Location>
</VirtualHost>
#监视apache服务器状态
扩展状态
SetHandler服务器状态
命令拒绝,允许
全盘否定
允许从127.0.0.1开始

然后将
Allow from
更改为您的IP,然后您可以访问并获得apache的摘要信息页面。当您看到其中一个僵尸并查看apache认为该进程在做什么时,请尝试这样做。

我在非常简单的mod_perl 2模块中也看到了这一点。我不分叉任何东西,只需向客户机套接字写入一个字符串,然后返回OK。在我的CentOS 5.5 Linux虚拟机上仍然出现了一个不存在的进程,然后就消失了。这是我的源代码,您可以使用“telnet yourhost 843”并按ENTER键进行测试:

package SocketPolicy;

# Run: semanage port -a -t http_port_t -p tcp 843
# And add following lines to the httpd.conf
# Listen 843
# <VirtualHost _default_:843>
#       PerlModule                   SocketPolicy
#       PerlProcessConnectionHandler SocketPolicy
# </VirtualHost>

use strict;
use warnings FATAL => 'all';
use APR::Const(-compile => 'SO_NONBLOCK');
use APR::Socket();
use Apache2::ServerRec();
use Apache2::Connection();
use Apache2::Const(-compile => qw(OK DECLINED));

use constant POLICY =>
qq{<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>
<allow-access-from domain="*" to-ports="8080"/>
</cross-domain-policy>
\0};

sub handler {
        my $conn   = shift;
        my $socket = $conn->client_socket();
        my $offset = 0;

        # set the socket to the blocking mode
        $socket->opt_set(APR::Const::SO_NONBLOCK => 0);

        do {
                my $nbytes = $socket->send(substr(POLICY, $offset), length(POLICY) - $offset);
                # client connection closed or interrupted
                return Apache2::Const::DECLINED unless $nbytes;
                $offset += $nbytes;
        } while ($offset < length(POLICY));

        my $slog = $conn->base_server()->log();
        $slog->warn('served socket policy to: ', $conn->remote_ip());
        return Apache2::Const::OK;
}

1;
package-SocketPolicy;
#运行:semanage port-a-t http_port_t-ptcp 843
#并将以下行添加到httpd.conf
#听着
# 
#PerlModule插座政策
#PerlProcessConnectionHandler套接字策略
# 
严格使用;
使用警告致命=>“全部”;
使用APR::Const(-compile=>'SO_NONBLOCK');
使用APR::Socket();
使用Apache2::ServerRec();
使用Apache2::Connection();
使用Apache2::Const(-compile=>qw(OK));
使用常量策略=>
qq{
\0};
副处理器{
我的$conn=班次;
my$socket=$conn->client_socket();
我的$offset=0;
#将套接字设置为阻塞模式
$socket->opt_set(APR::Const::SO_NONBLOCK=>0);
做{
my$nbytes=$socket->send(substr(策略,$offset),length(策略)-$offset);
#客户端连接已关闭或中断
返回Apache2::Const::拒绝,除非$n字节;
$offset+=$n字节;
}而($offsetbase_server()->log();
$slog->warn($conn->remote_ip());
返回Apache2::Const::OK;
}
1.

谢谢你,罗布。我可以寄给你所有的源代码。你想看看吗?然而,有很多东西需要阅读,大约30个文件。我已经在帖子中添加了我们系统使用的CPAN模块列表,请参见上文。此外,僵尸进程的pid与Apache2 pid匹配。在我看来,僵尸进程是Apache mod_perl进程,而不是由mod_perl代码生成的另一个进程。不,我不需要查看您的所有代码。感谢CPAN模块。我没有看到任何明显会分叉的东西,但我以前很惊讶。至于pid,如果您在mod_perl下分叉,那么父级和子级都将显示为apache的实例,而不是代码的实例。尝试添加$SIG{CHLD}='IGNORE';在代码的早期(可能在BEGIN块中)。如果这消除了僵尸,你就知道有东西在暗中分叉。谢谢你的提示!我添加了$SIG{CHLD}='IGNORE';要开始启动脚本的块(server.pl)。不幸的是,已经失效的进程仍然出现在顶部。请参阅我对该主题的更新。我已经添加了“top”行和access.log记录(我已经添加了pid作为日志条目的第一个参数)。PID匹配,因此失效的进程实际上是mod_perl apache2进程。Rob,非常感谢!我不知道服务器状态功能。我的武器库里还有一个工具。我能抓住僵尸好几次。但我不知道服务器状态的转储如何帮助我们找到问题的根源。我已经从服务器状态页附加了3行。它们都属于不同的僵尸进程。
# Monitor apache server status
ExtendedStatus On
<VirtualHost 127.0.0.1:80>
    <Location /server-status>
        SetHandler server-status
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Location>
</VirtualHost>
package SocketPolicy;

# Run: semanage port -a -t http_port_t -p tcp 843
# And add following lines to the httpd.conf
# Listen 843
# <VirtualHost _default_:843>
#       PerlModule                   SocketPolicy
#       PerlProcessConnectionHandler SocketPolicy
# </VirtualHost>

use strict;
use warnings FATAL => 'all';
use APR::Const(-compile => 'SO_NONBLOCK');
use APR::Socket();
use Apache2::ServerRec();
use Apache2::Connection();
use Apache2::Const(-compile => qw(OK DECLINED));

use constant POLICY =>
qq{<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>
<allow-access-from domain="*" to-ports="8080"/>
</cross-domain-policy>
\0};

sub handler {
        my $conn   = shift;
        my $socket = $conn->client_socket();
        my $offset = 0;

        # set the socket to the blocking mode
        $socket->opt_set(APR::Const::SO_NONBLOCK => 0);

        do {
                my $nbytes = $socket->send(substr(POLICY, $offset), length(POLICY) - $offset);
                # client connection closed or interrupted
                return Apache2::Const::DECLINED unless $nbytes;
                $offset += $nbytes;
        } while ($offset < length(POLICY));

        my $slog = $conn->base_server()->log();
        $slog->warn('served socket policy to: ', $conn->remote_ip());
        return Apache2::Const::OK;
}

1;