読者です 読者をやめる 読者になる 読者になる

mod_wsgiとlighttpd+FastCGIの速度比較

Django lighttpd Apache

mod_wsgilighttpd+FastCGIでのDjangoアプリケーションの速度比較を行う。環境はCentOS 5.2/Python2.5.3、Apacheが2.2.3とmod_wsgi2.3、lighttpdは1.4.20。

テストに用いたDjangoアプリケーション

$ django-admin.py startproject bench

で新規にプロジェクトを作成し、urls.pyを次のような内容にする。

from django.conf.urls.defaults import *
from django.http import HttpResponse

def default(req):
    content = u"0123456789" * 1000
    return HttpResponse(content, mimetype='text/plain')

urlpatterns = patterns('',
    (r'', default),
)

mod_wsgiの設定

mod_wsgi用に次のような起動スクリプトを用意する。

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'bench.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Apache/mod_wsgiの設定は考えられる限り最小で、次のようにした。mod_wsgiはembedモードで動かしている。

PidFile "/etc/httpd/run/httpd.pid"

Timeout 120

KeepAlive Off

StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  4000

User apache
Group apache

DocumentRoot "/var/www/html"

ErrorLog logs/error_log
LogLevel error

# mod_wsgi settings
LoadModule wsgi_module modules/mod_wsgi.so

WSGIPythonHome  /usr
WSGIPythonPath  /path/to/app
WSGIScriptAlias / /path/to/app/bench/modwsgi.py
WSGIScriptReloading Off
WSGIPythonOptimize 1

lighttpdの設定

通常通り、manage.py runfcgiで次のようにFastCGIプロセスを起動。

$ python manage.py runfcgi method=prefork host=127.0.0.1 port=9000

lighttpd側は、

$HTTP["host"] == "fcgi.example.com" {
 server.document-root = "/var/www/html"

 fastcgi.server = (
   "/dispatch.fcgi" => (
     "" => (
       "host" => "127.0.0.1",
       "port" => 9000,
       "check-local" => "disable",
     )
   )
 )
 url.rewrite-once = (
  "^(/.*)$" => "/dispatch.fcgi$1",
 )
}

比較

abを使って、まずmod_wsgiの方を計測。

$ ab -n 100 http://wsgi.example.com/
... 略
Requests per second:    316.08 [#/sec] (mean)
Time per request:       3.164 [ms] (mean)
Time per request:       3.164 [ms] (mean, across all concurrent requests)
Transfer rate:          3122.91 [Kbytes/sec] received

次に、lighttpd+FastCGI

$ ab -n 100 http://fcgi.example.com/
... 略
Requests per second:    170.46 [#/sec] (mean)
Time per request:       5.866 [ms] (mean)
Time per request:       5.866 [ms] (mean, across all concurrent requests)
Transfer rate:          1685.87 [Kbytes/sec] received

mod_wsgiの方が50%以上速い?

最初このエントリを書き始めた前の段階では、lighttpd+FastCGIの方が10-20%速いという結果だったので、何かおかしい気がする・・・要追試。

(追記)gumiの実際のコードを使って試してみたが、mod_wsgiFastCGIで有意な差が出なかった。

  • DBの読み書きが発生する現実世界のアプリケーションでは、mod_wsgiのパフォーマンス上の優位はほとんど意味をなさなくなる。
  • gumiのコードの問題でmod_wsgiの性能を最大限に引き出せていない

のどちらかか。

mod_wsgiの方がメリットが大きいのは明らかなので、前者であることを願いたい。

mod_wsgiのembedモードとdaemonモードの比較

上記のmod_wsgi embedモードをdaemonモード(processes=2 threads=15)に変えて、同様のベンチマークを行った結果。

$ ab -n 100 http://wsgi.example.com/
... 略
Requests per second:    230.84 [#/sec] (mean)
Time per request:       4.332 [ms] (mean)
Time per request:       4.332 [ms] (mean, across all concurrent requests)
Transfer rate:          2285.34 [Kbytes/sec] received

daemonモードよりembedモードの方が速いというのは、以前ちょと試したときにも経験したことなので、納得できる数値。