fastcgi-nginx vs mod_wsgi-apache

"mod_python 終了のお知らせ" を受け、もともとリソース不足だった既存の Django アプリケーション郡のサーバをリプレイスすることにしました。リプレイス要件↓

  • パフォーマンスが高いのにしたい
  • アプリケーションの変更は必要最小限にしたい
  • URL 類は既存のアプリケーションを引継ぐ: 複数プロジェクトをサブディレクトリーで運用していて、 "django.root" で複数プロジェクトを切り分けている

環境設定について

これは apache - mod_wsgi が簡単すぎます。


nginx - fastcgi

nginx - fastcgi 構成の場合は、init.d への登録、 daemontools を利用 (弊社は mod_python 以外はこれ)。

nginx の設定

/etc/nginx/fastcgi_params

fastcgi_read_timeout 180;
send_timeout 180;

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;
fastcgi_param  PATH_INFO          $fastcgi_script_name;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

fastcgi_pass_header Authorization;
fastcgi_intercept_errors off;

/etc/nginx/sites-enabled/default

server {
        listen   80;
        server_name  example.com;

        access_log  /var/log/nginx/example.com.access.log;

        # No www ! <- www を付けたくない場合の設定
        if ($host = 'www.example.com' ) {
                rewrite  ^/(.*)$  http://example.com/$1  permanent;
        }

        # Django の設定 <- 各 Django プロジェクトはポートで分ける
        location / {
                include /etc/nginx/fastcgi_params;
                fastcgi_pass 127.0.0.1:8080;
        }

        # Admin sites の設定 <- ローカルからに限定する
        location /admin {
                include /etc/nginx/fastcgi_params;
                fastcgi_pass 127.0.0.1:8080;

                allow [LOCAL_IP_ADDRESS];
                deny all;
        }

        # Static Files
        location /static {
                root   /path/to/staticfiles;
                access_log off; # アクセスログいらない
        }

        # Admin medias
        location /media {
                root   /path/to/django/contrib/admin/media;
                access_log off; # アクセスログいらない
        }
}
fastcgi の起動を init.d に登録

Django FastCGI init.d script for Linux を参考に、init.d スクリプトを作成し、反映する。

update-rc.d /etc/init.d/fastcgi defaults
daemontools の設定
# パッケージ名は daemontools or svtools のいずれか
sudo aptitude install daemontools daemontools-run

プロジェクト毎に、デーモンツールを作成する。
/etc/service/[PROJECT]/run

#!/bin/sh
#
#### SERVER SPECIFIC CONFIGURATION
SITE=[PROJECT]
HOST=127.0.0.1
PORT=[PORT]

SITES_PATH=/var/django
ENVIRONMENT_PATH=$SITES_PATH/environment
RUNFILES_PATH=/var/run/django
RUN_AS=www-data
MAXREQUESTS=1000

#### DO NOT CHANGE ANYTHING AFTER THIS LINE!
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="[PROJECT DESCRIPTION]"

cd $SITES_PATH/$SITE

# find python binary to use
if [ -f $ENVIRONMENT_PATH/$SITE/bin/python ]; then
    PYTHON=$ENVIRONMENT_PATH/$SITE/bin/python
else
    PYTHON=`which python`
fi

exec 2>&1

exec setuidgid $RUN_AS \
    /usr/bin/env -- $PYTHON \
    $SITES_PATH/$SITE/manage.py runfcgi \
    protocol=fcgi method=threaded maxrequests=$MAXREQUESTS \
    host=$HOST port=$PORT \
    pidfile=$RUNFILES_PATH/$SITE.pid \
    daemonize=false

chmod -R 777 $RUNFILES_PATH

mod_wsgi - apache
wsgi 用スクリプトの作成

各 Django アプリケーションごとに作成します。settings.py と同一階層に置くことを前提。

#!/usr/bin/python
# -*- encoding: utf-8 -*-
# wsgi_handler.py

import sys
import os

# print デバッグとかしてるとこけるから、追加しちゃった。
sys.stdout = sys.stderr

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/..')
os.environ['DJANGO_SETTINGS_MODULE'] = '[PROJECT].settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()
mod_wsgi の設定
sudo aptitude install libapache2-mod-wsgi
<VirtualHost *:80>
        ServerAdmin mail@example.com
        ServerName example.com

        DocumentRoot /var/www

        # Django settings
        WSGIScriptAlias / /path/to/project/wsgi_handler.py

        ErrorLog /var/log/apache2/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog /var/log/apache2/access.log combined

</VirtualHost>

daemon mode で起動したい場合の設定は、id:pyxis-dev さんのサイトが参考になります。私も daemon mode で運用しています。


パフォーマンスについて

結論から言うと、fastcgi も mod_wsgi も uwsgi もパフォーマンスに大きな差はありません (mod_python よりは早い) でした。パフォーマンスの差異については、 id:perezvon さんや Alexander Solovyov さんのサイト (英語) 等も参考になります。私がテストした環境だと、初回アクセス時のみ fastcgi の方が若干早かったですが、やはりその後は誤差の範囲内です。

mod_python からの移行について (URL とか)

前述のように、複数の Django プロジェクトをサブディレクトリで運用している場合は、 mod_wsgi の方が簡単です。 mod_python でいうところの "django.root" は mod_wsgi では以下のように設定できます。

# mod_python
<Location "/mysite/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonOption django.root /mysite
    PythonDebug On
</Location>
<Location "/mysite2/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite2.settings
    PythonOption django.root /mysite2
    PythonDebug On
</Location>
# mod_wsgi
<VirtualHost *:80>
        WSGIScriptAlias /mysite /path/to/django/mysite/wsgi_handler.py
        WSGIScriptAlias /mysite2 /path/to/django/mysite2/wsgi_handler.py
</VirtualHost>

fastcgi の場合は、rewrite の利用や、FORCE_SCRIPT_NAME で置き換えるか、 urls.py を書き換える必要があります。めんどい・・・。

ということで mod_wsgi を使うことにしましたよ!

コメント

このブログの人気の投稿

Python から Win32 API 経由で印刷する

財務諸表 (Financial Statements)

Django と Python 3 - #python_adv