【问题标题】:Apache/mod_wsgi process dies unexpectedlyApache/mod_wsgi 进程意外死亡
【发布时间】:2026-01-26 11:15:02
【问题描述】:

我正在测试我的 Python Flask Web 应用程序在 Apache Web 服务器上运行的限制,方法是发出一个需要 30 多分钟才能完成的请求。该请求需要对 MySQL 数据库的数千个数据库请求(一个接一个)。我知道这应该在理想情况下作为 apache 服务器之外的一个单独的异步进程运行,但现在让我们忽略它。我遇到的问题是,虽然当我在我的 mac 上测试它时它完全运行,但在 linux 服务器(AWS EC2 上的 Amazon linux)上运行它时它突然死亡。我一直无法弄清楚到底是什么杀死了它。我已经检查过服务器没有内存不足。该过程使用很少的 RAM。我找不到任何对我有意义的 Apache 配置参数或任何错误消息(即使在将 apache logLevel 设置为调试之后)。请我在哪里寻找帮助。以下是有关我的设置的更多详细信息:


运行时间

服务器:分别在 8 分钟、27 分钟、21 分钟和 22 分钟后死亡。请注意,这些运行大部分都在 UAT 服务器上,这是服务器正在处理的唯一请求。

Mac:它的运行速度比在服务器上运行要慢得多。该过程成功运行,耗时 2 小时 47 分钟。


Linux 服务器详情:
2 个虚拟 CPU 和 4GB RAM

操作系统uname -a 的输出)
Linux ip-172-31-63-211 3.14.44-32.39.amzn1.x86_64 #1 SMP Thu Jun 11 20:33:38 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Apache 错误日志: https://drive.google.com/file/d/0B3XXZfJyzJYsNkFDU3hJekRRUlU/view?usp=sharing

Apache 配置文件: https://drive.google.com/file/d/0B3XXZfJyzJYsM2lhSmxfVVRNNjQ/view?usp=sharing

Apache 版本apachectl -V 的输出)

Server version: Apache/2.4.23 (Amazon)  
Server built:   Jul 29 2016 21:42:17  
Server's Module Magic Number: 20120211:61  
Server loaded:  APR 1.5.1, APR-UTIL 1.4.1  
Compiled using: APR 1.5.1, APR-UTIL 1.4.1  
Architecture:   64-bit  
Server MPM:     prefork  
  threaded:     no  
    forked:     yes (variable process count)  
Server compiled with....  
 -D APR_HAS_SENDFILE  
 -D APR_HAS_MMAP  
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)  
 -D APR_USE_SYSVSEM_SERIALIZE  
 -D APR_USE_PTHREAD_SERIALIZE  
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT  
 -D APR_HAS_OTHER_CHILD  
 -D AP_HAVE_RELIABLE_PIPED_LOGS  
 -D DYNAMIC_MODULE_LIMIT=256  
 -D HTTPD_ROOT="/etc/httpd"  
 -D SUEXEC_BIN="/usr/sbin/suexec"  
 -D DEFAULT_PIDLOG="/var/run/httpd/httpd.pid"  
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"  
 -D DEFAULT_ERRORLOG="logs/error_log"  
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"  
 -D SERVER_CONFIG_FILE="conf/httpd.conf"  

Mac 详细信息:

Apache 配置文件: https://drive.google.com/file/d/0B3XXZfJyzJYsRUd6NW5NY3lON1U/view?usp=sharing

Apache 版本apachectl -V 的输出)

Server version: Apache/2.4.18 (Unix)  
Server built:   Feb 20 2016 20:03:19  
Server's Module Magic Number: 20120211:52  
Server loaded:  APR 1.4.8, APR-UTIL 1.5.2  
Compiled using: APR 1.4.8, APR-UTIL 1.5.2  
Architecture:   64-bit  
Server MPM:     prefork  
  threaded:     no  
    forked:     yes (variable process count)  
Server compiled with....  
 -D APR_HAS_SENDFILE  
 -D APR_HAS_MMAP  
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)  
 -D APR_USE_FLOCK_SERIALIZE  
 -D APR_USE_PTHREAD_SERIALIZE  
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT  
 -D APR_HAS_OTHER_CHILD  
 -D AP_HAVE_RELIABLE_PIPED_LOGS  
 -D DYNAMIC_MODULE_LIMIT=256  
 -D HTTPD_ROOT="/usr"  
 -D SUEXEC_BIN="/usr/bin/suexec"  
 -D DEFAULT_PIDLOG="/private/var/run/httpd.pid"  
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"  
 -D DEFAULT_ERRORLOG="logs/error_log"  
 -D AP_TYPES_CONFIG_FILE="/private/etc/apache2/mime.types"  
 -D SERVER_CONFIG_FILE="/private/etc/apache2/httpd.conf"  

【问题讨论】:

  • 根据您提供的信息,任何人现在能做的最好的事情就是猜测,因为没有足够的信息继续下去。至少将 Apache 的 LogLevel 设置为 info 并查看 mod_wsgi 关于进程重启的说法。还要验证您实际上正在使用 mod_wsgi 守护程序模式,正如已经指出的那样可能是一个问题。见modwsgi.readthedocs.io/en/develop/user-guides/…

标签: apache python-2.7 amazon-ec2 flask mod-wsgi


【解决方案1】:

如果您使用 mod_wsgi 的嵌入式模式,Apache 会控制进程的生命周期,并且如果它认为由于流量不足而不再需要某个进程,则可以回收它们。

您可能会想“但我使用的是守护程序模式而不是嵌入式模式”,但事实是您并没有这样做,因为您的配置是错误的。你有:

<VirtualHost *:5010>
    ServerName localhost

    WSGIDaemonProcess entry user=kesiena group=staff threads=5
    WSGIScriptAlias "/" "/Users/kesiena/Dropbox (MIT)/Sites/onetext/onetext.local.wsgi"

    <directory "/Users/kesiena/Dropbox (MIT)/Sites/onetext/app">
        WSGIProcessGroup start
        WSGIApplicationGroup %{GLOBAL}
        WSGIScriptReloading On
        Order deny,allow
        Allow from all
    </directory>
</virtualhost>

Directory 块不使用与WSGIScriptAlias 中的路径匹配的目录,因此不适用。

用途:

<VirtualHost *:5010>
    ServerName localhost

    WSGIDaemonProcess entry user=kesiena group=staff threads=5
    WSGIScriptAlias "/" "/Users/kesiena/Dropbox (MIT)/Sites/onetext/onetext.local.wsgi"

    <directory "/Users/kesiena/Dropbox (MIT)/Sites/onetext">
        WSGIProcessGroup start
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </directory>
</virtualhost>

在没有匹配的情况下它完全起作用的唯一原因是您通过以下方式打开了对 Apache 以在该目录中托管文件的访问权限:

<Directory "/Users/kesiena/Dropbox (MIT)/Sites">
    Require all granted
</Directory>

DocumentRoot 设置为应用程序源代码所在的父目录是一种不好的做法。使用它的编写方式,我可能会进入不同的端口或VirtualHost 并下载您所有的应用程序代码。

不要将您的应用程序代码粘贴在针对DocumentRoot 列出的目录下。

顺便说一句,即使您让 WSGI 应用程序以守护程序模式运行,Apache 仍然可以回收它将用于代理对 mod_wsgi 的请求的工作进程。因此,即使您的长时间运行的请求在 WSGI 应用程序进程中继续运行,如果工作进程由于运行时间过长而在此期间被回收,它可能会在它开始发送响应时立即失败。

您绝对应该将长时间运行的操作外包给后端 Celery 任务队列或类似的。

【讨论】:

  • 感谢格雷厄姆的建议。值得注意的是,您指出的配置错误仅适用于我的 mac 上的配置(该过程实际运行成功的地方)。该过程在将 DocumentRoot 设置为不同位置的服务器上失败,如上面的链接所示。
  • DocumentRoot 与它的死无关,这是Directory 指令中的目录名称不匹配。 WSGIProcessGroup 指令从未应用于对 WSGI 应用程序的请求。
【解决方案2】:

您可能会遇到强制套接字关闭,尽管您给出的时间看起来不太可能。对于我在 Azure 上的一个项目,任何闲置约 3 分钟的连接都会被系统关闭。我相信这些闭包是在网络路由中的服务器之前完成的,因此无法禁用它们或增加超时。

【讨论】:

  • 谢谢,但这似乎不太可能。我通过修改流程来测试这一点,以便在请求进入时立即向客户端发送响应,然后分离一个单独的线程继续处理服务器上的数据。这个单独的线程仍然突然死亡。
【解决方案3】:

嗯,棘手的问题。

猜测1:我曾经遇到过类似的问题。你玩过你的 KeepAlive 时间吗?将其设置为 60 分钟或更长时间并测试以查看问题是否仍然存在。更多细节在这里https://httpd.apache.org/docs/2.4/de/mod/core.html

猜想2:亚马逊能否在后台“移动”你的机器,从而中断你的数据库连接或flask无法处理虚拟机的“卸载”和“加载”?

【讨论】:

  • 我会调查 1。我怀疑 2,因为这种情况一直在发生。谢谢