【问题标题】:Django+Apache+ModWSGI Hangs IndefinitelyDjango+Apache+ModWSGI 无限期挂起
【发布时间】:2018-04-08 16:46:42
【问题描述】:

我有一个 Django 1.11 站点,由 Ubuntu 16 上的 Apache 2.4.18 + ModWSGI 提供服务,但它无限期挂起。奇怪的是,如果我停止 Apache,它才会返回请求,从而完美地呈现页面,这意味着 Django 正在正确返回请求,但是某些东西阻止了 Apache 发送数据。

我的 Apache 站点.conf:

<VirtualHost *:80>
    ServerName www.mysite.com
    ServerAlias www.mysite.com
    ServerAdmin sysadmin@mysite.com
    DocumentRoot /usr/local/mysite

    AllowEncodedSlashes On

    Alias /media/ /usr/local/mysite/media/
    Alias /static/ /usr/local/mysite/static/

    <Directory /usr/local/mysite>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from all
        # New directive needed in Apache 2.4.3.
        Require all granted
    </Directory>

    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>

    LogLevel debug
    ErrorLog ${APACHE_LOG_DIR}/mysite-error.log
    CustomLog ${APACHE_LOG_DIR}/mysite-access.log combined

    # Stop GIL deadlocks from crashing Python/Modwsgi due to Python C-extensions?
    # Without this, you may get a "Premature end of script" error.
    # https://code.google.com/p/modwsgi/wiki/ApplicationIssues#Python_Simplified_GIL_State_API
    WSGIApplicationGroup %{GLOBAL}

    WSGIDaemonProcess www.mysite.com python-path=/usr/local/mysite/.env/lib/python2.7/site-packages processes=1  display-name=%{GROUP} user=www-data group=www-data
    WSGIProcessGroup www.mysite.com
    WSGIScriptAlias / /usr/local/mysite/wsgi/mysite.wsgi

    <Directory /usr/local/mysite/wsgi>
        Order allow,deny
        Allow from all
    </Directory>

</VirtualHost>

我的 Django wsgi:

import os
import time
import traceback
import signal
import sys

from django.core.wsgi import get_wsgi_application

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings.settings'
os.environ['CELERY_LOADER'] = 'django'

sys.path.append(os.path.join(os.path.realpath(os.path.dirname(__file__)), '../src'))
sys.path.append(os.path.join(os.path.realpath(os.path.dirname(__file__)), '../src/mysite'))

try:
    application = get_wsgi_application()
    print 'WSGI without exception'
except Exception:
    print 'handling WSGI exception'
    # Error loading applications
    if 'mod_wsgi' in sys.modules:
        traceback.print_exc()
        os.kill(os.getpid(), signal.SIGINT)
        time.sleep(2.5)

我的 Apache 日志中唯一感兴趣的是几行,例如:

[Fri Oct 27 02:37:08.079977 2017] [wsgi:error] [pid 14053:tid 139644805011200] [client 10.182.122.159:45695] Timeout when reading response headers from daemon process 'www.mysite.com': /usr/local/mysite/wsgi/mysite.wsgi

显然,似乎有些东西没有收到正确的信号,导致它一直等到发生超时,但我无法弄清楚原因是什么。我尝试重构我的 Apache 配置,并禁用我的 Django 应用程序中可能超时的部分,但没有任何效果。我该如何诊断?

【问题讨论】:

    标签: python django apache mod-wsgi


    【解决方案1】:

    您的请求很可能被阻止并且永远不会返回。与信号无关,或者至少与 Apache 自己对信号的使用无关。关闭信号可能会中断您的请求被阻止的某些系统调用。

    WSGIDaemonProcess指令中添加选项:

    request-timeout=60
    

    并监控日志以查看 mod_wsgi 守护进程是否由于请求超时而重新启动。

    因为您使用的是默认为 15 个线程的单个进程,因为请求超时是如何应用到所有请求处理程序的平均值的,如果只有一个请求处理程序无限期阻塞,则强制重启最多需要 15 分钟的过程。如果多个请求被阻塞,那么会比这更快。

    我在这里假设 60 秒比您期望的运行时间要长。如果您的请求应该总是比这更快地处理,请将其设置得更低。

    您的 WSGI 脚本文件中也不需要 try/except/kill 的内容。而不是添加到WSGIDaemonProcess 选项:

    startup-timeout=15
    

    【讨论】:

    • try/except/kill 的东西是必要的,否则 ModWSGI 会掩盖日志中的 Python 异常。我从另一个 SO 对问题的回答中学到了这个技巧,“为什么我的 Apache 日志中看不到 Django 异常?”
    • 另外,startup-timeout 似乎不是一个有效的 Apache 选项。这样,Apache 拒绝加载我的配置。
    • 为什么建议使用request-timeout=60?我已经知道我的请求正在超时,正如我发布的日志条目所证明的那样。我正在尝试找出超时的原因。
    • 有了request-timeout 指令,我现在可以看到一些日志条目,例如Truncated or oversized response headers received from daemon process mysite。谷歌搜索表明它可能是由任何数量的问题引起的。
    • 如果 mod_wsgi 守护进程由于请求超时而被强制重启,您将看到这些消息。您还应该看到一堆其他消息,因此请务必检查日志。如果需要,也检查主 Apache 日志,但我认为消息应该在虚拟主机日志中。
    猜你喜欢
    • 2011-02-11
    • 1970-01-01
    • 2017-06-29
    • 2011-05-07
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    相关资源
    最近更新 更多