Eu tenho experimentado bastante tempo com uma configuração "típica" de django em nginx + apache2 + mod_wsgi + memcached (+ postgresql) (lendo o documento e algumas questões sobre SO e SF, veja os comentários)
Desde que eu ainda estou insatisfeito com o comportamento (definitivamente por causa de uma má má configuração da minha parte), eu gostaria de saber como seria uma boa configuração com essas hipóteses:
- Quad-Core Xeon 2,8 GHz
- 8 GB de memória
- vários projetos de django (algo especial relacionado a isso?)
Estes são trechos dos meus confs atuais:
EDIT: Eu adicionei mais coisas para completar, mas seguindo a sugestão de Graham, eu irei acompanhar a lista de discussão do wsgi
apache 2 (> apache2 -v)
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"
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>
wsgi.py
Atualmente usando a versão 3.3 criada a partir da fonte
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)'
estrutura de pastas
caso seja importante (ligeiramente encurtado)
/home/www-data/projectN/var/logs
/project (contains manage.py, wsgi.py, settings.py)
/project/apps (all the project ups are here)
/django
/libs
Por favor, perdoe-me com antecedência se eu negligenciei algo óbvio.
Minha principal questão é sobre as configurações do wsgi apache2. Estão bem? 25 threads são / ok / number com um quad core para um único projeto django? Ainda está tudo bem com vários projetos de django em diferentes hosts virtuais? Devo especificar 'process'? Qualquer outra diretriz que devo acrescentar? Há algo realmente ruim no arquivo wsgi.py?
Eu tenho lido sobre possíveis problemas com o arquivo wsgi.py padrão, devo mudar para isso?
Ou .. este conf só deveria estar funcionando bem, e eu deveria procurar por problemas em algum outro lugar?
Então, o que quero dizer com "insatisfeito": bem, muitas vezes fico com CPU WAIT bastante alta; mas o que é pior, é que, com relativa frequência, o apache2 fica preso. Ele simplesmente não responde mais e precisa ser reiniciado. Eu configurei um monitor para cuidar disso, mas não é uma solução real.
Eu tenho me perguntado se é um problema com o acesso ao banco de dados (postgresql) sob carga pesada, mas mesmo se fosse, por que os processos do apache2 ficariam presos?
Além desses dois problemas, o desempenho é ótimo no geral. Eu até tentei New Relic e obtive resultados médios muito bons.
edit Eu mesmo não poderei responder, pois mudei temporariamente para um ambiente nginx + gunicorn.
Acompanhe também os grupos do Google para minha situação pessoal e problemas! Parece que o Graham está, é claro, muito ocupado (o mod_wsgi é um projeto paralelo gratuito!), Mas mudar para o Read The Docs parece ótimo, e resolver esse problema seria totalmente incrível. Isso e o novo Apache 2.4 podem me fazer reconsiderar o melhor combo (atualmente nginx + gunicorn, então eu poderia abandonar o nginx para uma configuração de verniz + apache + mod_wsgi)