我经常在nginx + apache2 + mod_wsgi + memcached(+ postgresql)上使用“典型”的django设置进行实验(阅读文档以及SO和SF上的一些问题,参见注释)
由于我仍然不满意的行为(绝对是因为我的一些错误configuration),我想知道这些假设是什么样子的好configuration:
这些摘录形成我目前的confs:
编辑:我已经添加了更多的东西,使完成,但遵循格雷厄姆的build议,我将在wsgi邮件列表
Server version: Apache/2.2.12 (Ubuntu) Server built: Nov 18 2010 21:16:51 Server's Module Magic Number: 20051115:23 Server loaded: APR 1.3.8, APR-Util 1.3.9 Compiled using: APR 1.3.8, APR-Util 1.3.9 Architecture: 64-bit Server MPM: Worker threaded: yes (fixed thread count) forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/worker" -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=128 -D HTTPD_ROOT="" -D SUEXEC_BIN="/usr/lib/apache2/suexec" -D DEFAULT_PIDLOG="/var/run/apache2.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="/etc/apache2/mime.types" -D SERVER_CONFIG_FILE="/etc/apache2/apache2.conf"
PidFile ${APACHE_PID_FILE} Timeout 60 KeepAlive Off ServerSignature Off ServerTokens Prod #MaxKeepAliveRequests 100 #KeepAliveTimeout 15 # worker MPM <IfModule mpm_worker_module> StartServers 2 ServerLimit 4 MinSpareThreads 2 MaxSpareThreads 4 ThreadLimit 32 ThreadsPerChild 16 MaxClients 64#128 MaxRequestsPerChild 10000 </IfModule>
…
SetEnv VHOST null #WSGIPythonOptimize 2 <VirtualHost *:8082> ServerName subdomain.domain.com ServerAlias www.domain.com SetEnv VHOST subdomain.domain AddDefaultCharset UTF-8 ServerSignature Off LogFormat "%{X-Real-IP}i %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" custom ErrorLog /home/project1/var/logs/apache_error.log CustomLog /home/project1/var/logs/apache_access.log custom AllowEncodedSlashes On WSGIDaemonProcess subdomain.domain user=www-data group=www-data threads=25 WSGIScriptAlias / /home/project1/project/wsgi.py WSGIProcessGroup %{ENV:VHOST} </VirtualHost>
目前使用从源代码构build的3.3版本
import os import sys # setting all the right paths.... _realpath = os.path.realpath(os.path.dirname(__file__)) _public_html = os.path.normpath(os.path.join(_realpath, '../')) sys.path.append(_realpath) sys.path.append(os.path.normpath(os.path.join(_realpath, 'apps'))) sys.path.append(os.path.normpath(_public_html)) sys.path.append(os.path.normpath(os.path.join(_public_html, 'libs'))) sys.path.append(os.path.normpath(os.path.join(_public_html, 'django'))) os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' import django.core.handlers.wsgi _application = django.core.handlers.wsgi.WSGIHandler() def application(environ, start_response): """ Launches django passing over some environment (domain name) settings """ application_group = environ['mod_wsgi.application_group'] """ wsgi application group is required. It's also used to generate the HOST.DOMAIN.TLD:PORT parameters to pass over """ assert application_group fields = application_group.replace('|', '').split(':') server_name = fields[0] os.environ['WSGI_APPLICATION_GROUP'] = application_group os.environ['WSGI_SERVER_NAME'] = server_name if len(fields) > 1 : os.environ['WSGI_PORT'] = fields[1] splitted = server_name.rsplit('.', 2) assert splitted >= 2 splited.reverse() if len(splitted) > 0 : os.environ['WSGI_TLD'] = splitted[0] if len(splitted) > 1 : os.environ['WSGI_DOMAIN'] = splitted[1] if len(splitted) > 2 : os.environ['WSGI_HOST'] = splitted[2] return _application(environ, start_response)`
如果有的话(实际上稍微缩短)
/home/www-data/projectN/var/logs /project (contains manage.py, wsgi.py, settings.py) /project/apps (all the project ups are here) /django /libs
如果我忽略了一些明显的事情,请提前原谅我。
我的主要问题是关于apache2的wsgi设置。 那些罚款? 是一个只有一个django项目的25个线程一个/好/数字与一个四核心? 在不同的虚拟主机上的几个Django项目还可以吗? 我应该指定“过程”吗? 我应该补充的其他指令? wsgi.py文件中有什么不好的吗?
我一直在阅读关于标准wsgi.py文件的潜在问题 ,我应该切换到?
或者..如果这个机会运行良好,我应该找其他地方的问题?
那么,我觉得“不满意”是什么意思呢? 但更糟的是,相对经常apache2卡住了。 它只是不回答,必须重新启动。 我已经build立了一个monit来处理这个问题,但这不是一个真正的解决scheme。 我一直想知道在重负载下数据库访问(postgresql)是否存在问题,但即使是这样,为什么apache2进程会卡住?
除了这两个问题,性能总的来说还是不错的。 我甚至尝试过New Relic,结果非常好。
编辑我暂时无法自己提供答案,暂时移到了nginx + gunicorn环境中。
也跟进谷歌组我的个人情况和问题! 听起来像Graham当然是非常忙碌(mod_wsgi是一个免费的项目!),但移动到阅读文档听起来不错,解决这个积压问题将是非常棒的。 这和新的Apache 2.4可能会让我重新考虑最好的组合(目前nginx + gunicorn,那么我可能会下降nginx的清漆+ Apache + mod_wsgi设置)
在Apache中启用mod_headers,然后添加到您的VirtualHost:
RequestHeader add X-Queue-Start "%t"
然后New Relic会在主概览图中显示排队时间。
这是Apachesubprocess首先接受请求和mod_wsgi守护进程处理请求之间的时间。 这可以用作请求积压的一个指示符,这又可以指示由于死锁的线程或等待在外部资源上的线程而导致的守护进程中的线程匮乏。
不幸的是,New Relic依靠完成请求报告数据的请求。 所以如果一个请求被卡住了,你就不会知道。 如果所有线程都卡住,守护进程将停止处理更多的请求。
问题是如果Apachesubprocess进程中的进程数/线程数小于100,守护进程进程监听器积压,那么所有这些线程也会卡住,并且你不会从Apache错误日志中知道,因为他们只是坐在那里等待守护进程接受从未发生的连接。 只有HTTP浏览器客户端会知道,当Apache子工作者套接字积压填满时,它将被拒绝连接。
在mod_wsgi 4.0中,我将增加为守护进程configuration监听程序积压的function,所以可以减less这个值,这样你可能会得到某种错误。 在mod_wsgi 4.0中已经有了新的选项来查找被阻塞的线程并自动重启守护进程,同时也转储了当时被阻塞的线程在代码中的栈跟踪。
为了得到你需要使用mod_wsgi 4.0 dev代码从mod_wsgi回购。 然后,您可以将WSGIDaemonProcess上的阻塞超时设置为60秒,当所有线程卡住时,它将执行重新启动和恢复以及转储堆栈跟踪。 我仍然在调整这一点,还有其他configuration选项与此相关,为什么不在这里描述。
mod_wsgi 4.0代码还具有一些其他function,可以在New Relic中使用自定义图表来跟踪越来越多的被阻塞的线程。 我不满意,需要改变一下,但是很稳定。
无论如何,跳转到mod_wsgi邮件列表进一步讨论。