我有一个 Django 网站,它大多数时候运行良好,内存使用情况稳定,如果没有一些奇怪的问题,我就不用担心,这些问题直到昨天才偶尔出现,并导致网站昨晚整个晚上都处于瘫痪状态。
配置:
- 德比安·兰尼
- Apache 2.2 预分叉
- mod_wsgi 的新功能
- Python 2.5.2
- Django 1.2.5
我得到的回溯:
[error] mod_wsgi (pid=7390): Exception occurred within sys.exitfunc().
[error] Traceback (most recent call last):
[error] File "/usr/lib/python2.5/atexit.py", line 24, in _run_exitfuncs
[error] func(*targs, **kargs)
[error] File "/usr/lib/python2.5/logging/__init__.py", line 1354, in shutdown
[error] h.flush()
[error] File "/usr/lib/python2.5/logging/__init__.py", line 731, in flush
[error] self.stream.flush()
[error] IOError: sys.stdout access restricted by mod_wsgi
上面的错误经常在我重启 Apache 或者 touch .wsgi 文件时产生,所以我并不太在意。下面这些比较有意思:
[error] [client ..] mod_wsgi (pid=8184): Exception occurred processing WSGI script '.../django.wsgi'.
[error] [client ..] Traceback (most recent call last):
[error] [client ..] File ".../django/core/handlers/wsgi.py", line 248, in __call__
[error] [client ..] response = self.get_response(request)
[error] [client ..] File ".../django/core/handlers/base.py", line 140, in get_response
[error] [client ..] receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
[error] [client ..] File "...django/dispatch/dispatcher.py", line 172, in send
[error] [client ..] response = receiver(signal=self, sender=sender, **named)
[error] [client ..] File "...django/db/transaction.py", line 299, in _commit_on_success
[error] [client ..] res = func(*args, **kw)
[error] [client ..] File ".../apps/utils/middleware.py", line 28, in exception_handler
[error] [client ..] 'url': request.get_full_path()
[error] [client ..] File "/usr/lib/python2.5/logging/__init__.py", line 1015, in error
[error] [client ..] apply(self._log, (ERROR, msg, args), kwargs)
[error] [client ..] File "/usr/lib/python2.5/logging/__init__.py", line 1101, in _log
[error] [client ..] self.handle(record)
[error] [client ..] File "/usr/lib/python2.5/logging/__init__.py", line 1111, in handle
[error] [client ..] self.callHandlers(record)
[error] [client ..] File "/usr/lib/python2.5/logging/__init__.py", line 1148, in callHandlers
[error] [client ..] hdlr.handle(record)
[error] [client ..] File "/usr/lib/python2.5/logging/__init__.py", line 655, in handle
[error] [client ..] self.emit(record)
[error] [client ..] File "../apps/py26_logging/handlers.py", line 394, in emit
[error] [client ..] self.stream.flush()
[error] [client ..] ValueError: I/O operation on closed file
一句话解释:因为我使用 logrotate 进行日志轮换,所以我将 logs.WatchedFileHandler 从 Python 2.6“反向移植”到项目中,放置在 中apps/py26_logging/handlers.py
,但我的猜测是,不是 WatchedFileHandler 导致了这个问题,它只受到更普遍的问题的影响 - 因为 95% 的时间它都运行良好。
无论如何,Apache 重启可以立即解决问题(当然直到下一次)。
我用于服务器监控的 ServerDensity 显示稳定的内存使用情况(直线),任何时候都有至少 500mb 的可用内存,进程数量也很稳定,而且当我的应用程序出现问题时,统计数据通常不会出现任何异常。
我尝试使用 ApacheBench 重现该问题,但除非我同时使用 100 个请求,否则我无法使任何单个请求失败:
并发级别:100 完成请求:10000 失败请求:1(连接:0、接收:0、长度:1、异常:0) 写入错误:0 非 2xx 响应:1
我不用说,这远远超出了通常的负载,并且 ServerDensity 统计数据大幅上升。
你们中有人看到这里熟悉的模式了吗?
答案1
我只能对IOError: sys.stdout access restricted by mod_wsgi
错误进行评论。您的 Django-App 中的某些内容写入了sys.stdout
mod_wsgi 限制的内容。通常,sys.stdout
WSGI 应用程序中不会发生任何输出。您可以WSGIRestrictStdout Off
在全局 Apache 配置(而不是 vhost)中使用作为创可贴。要获得永久而干净的解决方案,请删除任何print
或任何写入的内容sys.stdout
。有关更多详细信息,请查看mod_wsgi 文档。