Django与wsgi偶尔出现“脚本头部提前结束”错误

5 投票
1 回答
2406 浏览
提问于 2025-04-17 06:18

我有一个网站已经在Apache2上运行了几个月,期间偶尔会出现一些小问题,具体表现如下:

[Sat Nov 12 06:18:34 2011] [error] [client X.Y.Z.158] Premature end of script headers: sleepsoundly_wsgi.py
[Sat Nov 12 06:18:49 2011] [error] [client X.Y.Z.158] Premature end of script headers: sleepsoundly_wsgi.py

这个网站处理了成千上万的请求,没有问题,但偶尔会出现几次这样的情况,然后一切又恢复正常。这种情况发生在我上传大约300个文件(每个文件0.5MB)的时候。每次上传都是单独上传3个文件,一共225个文件上传得很好,但第226和227个文件失败了,然后第228个文件又正常上传了。这种情况并不是每次都会发生,也不是每次都是这些文件出问题。有一次,第291个文件失败了,其他的都正常。

我在日志中没有找到任何线索,只有这个难以理解的信息。

我检查过,机器上唯一的Python版本是2.7.1。我没有收到来自Django的邮件,也没有得到任何正常情况下可能出现的提示。我很好奇该如何开始排查这个问题。它会自动恢复,上传文件的程序也在继续运行。我该如何弄清楚到底发生了什么呢?

Server version: Apache/2.2.17 (Ubuntu)
Server built:   Sep  1 2011 09:25:26
mod_wsgi: Version: 3.3-2ubuntu2

Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)

wsgi.conf has no lines in it that are not commented out.

VirtualHost setup:
    WSGIDaemonProcess myemr user=mjones processes=1 maximum-requests=500 threads=15
    WSGIProcessGroup  myemr
    WSGIScriptAlias   / /var/www/Python/myemr/myemr/deploy/myemr_wsgi.py

myemr_wsgi.py
    from os.path import abspath, dirname, join
    import sys

    # For packages that don't play well with mod_wsgi
    sys.stdout = sys.stderr

    sys.path.insert(0, abspath(join(dirname(__file__), "../..")))
    sys.path.insert(0, abspath(join(dirname(__file__), "../../myemr")))
    sys.path.insert(0, abspath(join(dirname(__file__), "../../myemr/apps")))
    sys.path.insert(0, abspath(join(dirname(__file__), "../../lib/python2.7/site-packages/")))

    # We have to add both of these because they are  installed with git?
    sys.path.insert(0, abspath(join(dirname(__file__), "../../src/pinax/")))

    from django.core.handlers.wsgi import WSGIHandler
    import pinax.env

    # setup the environment for Django and Pinax
    pinax.env.setup_environ(project_path='myemr')

    # set application for WSGI processing
    application = WSGIHandler()

1 个回答

5

这个问题可能是因为你把“最大请求数”设置成了500。这样会导致mod_wsgi的守护进程定期重启。由于mod_wsgi的守护进程是多线程运行的,如果有请求卡住了,或者有请求运行时间过长,在重启时没有完成,就会被强制中止。然后,Apache的子进程会把这个看作是一个没有返回头信息的请求,从而出现你看到的那个错误信息。

所以,记住,除非你有很好的理由,比如内存使用失控,否则不要在生产环境中使用“最大请求数”这个选项。

mod_wsgi的4.0版本会有一个可选的、稍微优雅一点的重启选项,可以用来处理这种情况,但它也不能无限期等待,卡住的请求最终还是会被中止,你还是会看到那个错误信息。

顺便提一下,不要指定“processes=1”,因为默认就是一个进程。即使你设置了“processes=1”,也会导致“wsgi.multiprocess”被设置为True。只有在你有一个单独的进程,并且有多个Apache实例在负载均衡的情况下,才可以使用“processes=1”。

撰写回答