使用mod_wsgi冻结Django / Apache

时间:2011-09-23 16:44:09

标签: django apache nginx mod-wsgi

我有一个Django应用程序在Nginx后面运行2个负载均衡的mod_wsgi / Apache服务器(静态文件,反向代理/负载平衡)。

每隔几天,我的网站就会完全没有反应。我的猜测是,许多客户端正在请求阻止的URL。

这是我的配置

WSGIDaemonProcess web1 user=web1 group=web1 processes=8 threads=15 maximum-requests=500 python-path=/home/web1/django_env/lib/python2.6/site-packages display-name=%{GROUP}
WSGIProcessGroup web1
WSGIScriptAlias / /home/web1/django/wsgi/wsgi_handler.py

我尝试过只使用单个线程和更多进程,以及更多线程和单个进程。几乎我迟早会尝试的所有内容都会导致页面加载超时。

对于我可能尝试的任何建议?如果可以解决问题,我愿意尝试其他部署选项。

另外,有没有比Apache状态模块更好的监控mod_wsgi的方法?我一直在打:

 curl http://localhost:8080/server-status?auto

看着忙碌的工人数量作为我是否即将陷入困境的指标(我假设我的工作人员越多,目前正在进行越多的阻止行动)。

注意:其中一些请求是我为应用程序托管的REST Web服务。以某种方式通过Nginx对URL位置进行速率限制是否有意义?

3 个答案:

答案 0 :(得分:3)

使用:

http://code.google.com/p/modwsgi/wiki/DebuggingTechniques#Extracting_Python_Stack_Traces

嵌入您可以在您希望卡住请求并找出他们正在做的事情时触发的功能。可能这些请求会随着时间的推移而不是一次性发生,因此您可以定期执行,而不是等待完全失败。

作为故障保护,您可以添加选项:

inactivity-timeout=600

到WSGIDaemonProcess指令。

如果守护程序模式进程处于非活动状态10分钟,它将会重启守护进程模式进程。

不幸的是,目前这种情况发生在两种情况中。

第一个是10分钟内根本没有请求的地方,这个过程将重新启动。

第二个,也就是你想要启动的那个,就是如果所有请求线程都被阻止,并且没有人读取wsgi.input的任何输入,也没有任何响应内容产生,在10分钟内,该过程将再次自动重启。

这至少意味着你的过程应该自动恢复,你不会被叫到床上。因为您运行的是这么多进程,所以很可能它们不会同时被卡住,因此新请求不会注意到重启,因为其他进程仍将处理请求。

你应该解决的问题是你的超时时间有多低。您不希望它如此之低以至于进程将因为没有请求而重新启动,因为它将卸载应用程序和下一个请求,如果使用延迟加载将导致速度变慢。

我应该做的是实际添加一个新选项blocked-timeout,它专门检查在定义的时间段内被阻止的所有请求,因此将它与重新启动分开,因为根本没有请求。这会使其更加灵活,因为没有请求会因重新加载应用程序而带来自身问题而重新启动。

不幸的是,无法轻松实现适用于单个请求的请求超时,因为托管配置可能是多线程的。将Python异常注入请求不一定会解除对线程的阻塞,最终您必须终止进程并中断其他并发请求。因此阻塞超时可能更好。

另一个有趣的事情可能是我将内容添加到mod_wsgi中以报告由于阻止进程进入New Relic代理而导致的强制重启。那会非常酷,因为你可以在监控工具中看到它们。 : - )

答案 1 :(得分:0)

如果我已正确理解您的问题,您可以尝试以下选项:

  • 将URL提取出请求/响应周期(使用例如芹菜);
  • 增加线程数(它们可以比进程更好地处理这些块,因为它们消耗更少的内存);
  • 减少urllib2.urlopen的超时;
  • 尝试gevent或eventlet(他们会神奇地解决你的问题但会引入另一个微妙的问题)

我不认为这是一个部署问题,这更多的是代码问题,并且没有解决它的apache配置。

答案 2 :(得分:0)

我的工作遇到了类似的问题。最好的我们可以弄清楚应用程序的种族/死锁问题,导致mod_wsgi被卡住。通常会杀死一个或多个mod_wsgi进程会暂时解除它。

最佳解决方案是转向所有流程,无线程。我们与开发团队确认,他们所引入的一些Python库可能不是线程安全的。

尝试:

WSGIDaemonProcess web1 user = web1 group = web1 processes = 16 threads = 1 maximum-requests = 500 python-path = / home / web1 / django_env / lib / python2.6 / site-packages display-name =%{GROUP}

下行是,进程占用的内存比线程多。因此,我们通常最终会减少整体工人(因此16x1而不是8x15)。而且由于mod_wsgi几乎没有提供报告工作人员繁忙程度的信息,因此除了盲目调整你的工作量外,你还能解决SOL。

好处是,这个问题不再发生,应用程序再次完全可靠。

与PHP一样,不要使用线程实现,除非你确定它的安全......这意味着核心(通常是ok),框架,你自己的代码和任何东西否则你导入。 :)