web-dev-qa-db-ja.com

クアッドコア上のDjangoプロジェクト)のapache + mod_wsgi構成

私はかなり長い間、「典型的な」Django nginx + Apache2 + mod_wsgi + memcached(+ postgresql)の設定( ドキュメント といくつかの質問を読む)を試してきました。 on SOおよびSF、コメントを参照)

私はまだ動作に満足していないので(間違いなく私の側のいくつかの悪い設定ミスのために)、これらの仮説で良い設定がどのように見えるか知りたいです:

  • クアッドコアXeon2.8GHz
  • 8ギグメモリ
  • いくつかのDjangoプロジェクト(これに関連する特別なものはありますか?)

これらは私の現在のconfからの抜粋です:

編集:これを完了するためにさらに多くのものを追加しましたが、Grahamの提案に従って、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

現在、ソースから構築されたバージョン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

明らかなことを見落とした場合は、事前にご容赦ください。

私の主な質問は、Apache2wsgi設定についてです。それらは大丈夫ですか? 25スレッドは1つだけのクアッドコアを持つ/ ok /番号ですか?Djangoプロジェクト?異なる仮想ホスト上の複数のDjangoプロジェクトでも問題ありませんか? 'process'を指定しますか?追加する必要のある他のディレクティブはありますか?wsgi.pyファイルに本当に悪いものはありますか?

私は標準のwsgi.pyファイルで 潜在的な問題 について読んでいますが、それに切り替える必要がありますか?

または..このconfは正常に実行されている必要があり、どこか別の場所で問題を探す必要がありますか?

つまり、「不満」とはどういう意味ですか。まあ、私はしばしばかなり高いCPU待機を取得します。しかし、さらに悪いことに、Apache2が比較的頻繁にスタックします。応答しなくなったため、再起動する必要があります。私はそれを処理するためにmonitを設定しましたが、それは実際の解決策ではありません。負荷の高いデータベースアクセス(postgresql)に問題があるのではないかと思っていましたが、問題があったとしても、Apache2プロセスがスタックするのはなぜですか?

これらの2つの問題に加えて、パフォーマンスは全体的に優れています。 New Relicを試してみても、平均して非常に良い結果が得られました。

edit一時的にnginx + gunicorn環境に移行したため、自分で回答することはできません。

また、私の個人的な状況と問題については google groups をフォローアップしてください!もちろん、Grahamは本当に忙しいようですが(mod_wsgiはフリーサイドプロジェクトです!)、Read The Docsに移行するのは素晴らしいことであり、1つのバックログの問題を解決することは完全に素晴らしいことです。それと新しいApache2.4は、私に最高のコンボを再考させるかもしれません(現在、nginx + gunicorn、次にニス+ Apache + mod_wsgi設定のためにnginxをドロップするかもしれません)

2
Stefano

Apacheでmod_headersを有効にしてから、VirtualHostに追加します。

RequestHeader add X-Queue-Start "%t"

New Relicは、メインの概要チャートにキューイング時間を表示します。

これは、リクエストがApacheチャイルドワーカープロセスによって最初に受け入れられてから、mod_wsgiデーモンプロセスがリクエストを処理するまでの時間です。これは、要求がバックログされることを示す1つの指標として使用できます。これは、デッドロックされたスレッドまたは外部リソースで待機しているスレッドによるデーモンプロセスのスレッド不足を示す可能性があります。

残念ながら、New Relicは、リクエストの完了に依存して、そのリクエストのデータを報告します。したがって、リクエストがスタックした場合、それについてはわかりません。すべてのスレッドがスタックすると、デーモンプロセスはそれ以上の要求の処理を停止します。

問題は、Apacheの子ワーカープロセス全体のプロセス/スレッドの数が100未満の場合、デーモンプロセスリスナーのバックログであり、それらのスレッドもすべてスタックする可能性があり、Apacheエラーログからは待機しているだけなのでわかりません。決して起こらない接続を受け入れるデーモン。 Apacheの子ワーカーのソケットバックログがいっぱいになると接続が拒否されるため、HTTPブラウザークライアントのみが認識します。

Mod_wsgi 4.0では、デーモンプロセスのリスナーバックログを構成する機能を追加して、何らかのエラーが発生する可能性があるように減らすことができます。 mod_wsgi 4.0には、ブロックされたスレッドを検索し、デーモンプロセスを自動的に再起動し、ブロックされたスレッドがその時点でコード内にあった場所のスタックトレースをダンプする新しいオプションがすでにあります。

これを取得するには、mod_wsgiリポジトリのmod_wsgi4.0開発コードを使用する必要があります。次に、WSGIDaemonProcessのblocked-timeoutを60秒に設定すると、すべてのスレッドがスタックすると、再起動と回復が行われ、スタックトレースがダンプされます。まだこれを微調整しており、これに関連する他の構成オプションがあるので、ここで説明しないでください。

Mod_wsgi 4.0コードには、ブロックされたスレッドの数の増加を追跡するためにNewRelicのカスタムチャートで使用できる他の機能もいくつかあります。それに満足しておらず、少し変更する必要がありますが、安定しています。

とにかく、さらに議論するためにmod_wsgiメーリングリストにジャンプしてください。

2