Python で Web アプリケーションを開発する場合、WSGI という仕様に沿った形で作られているとアプリケーションのポータビリティが向上する。 WSGI の仕様に沿っているアプリケーションは、異なる実装の WSGI サーバであっても動作させることができるためだ。
今回は数ある WSGI サーバの中でも Apache httpd 上で動作することで有名な mod_wsgi について扱う。 この mod_wsgi にはふたつの動作モードがあり、それぞれ組み込みモード (embedded mode) とデーモンモード (daemon mode) という名前がついている。 今回は mod_wsgi を組み込みモードとデーモンモードのそれぞれで動作させた上で、両者がどのように異なるのかについて調べていく。
尚、今回の検証には CentOS7 を使った。
$ cat /etc/redhat-release CentOS Linux release 7.1.1503 (Core) $ uname -r 3.10.0-229.el7.x86_64
下準備
まずは mod_wsgi を使った動作確認ができるところまで持っていく。
mod_wsgi を yum でインストールする。
$ sudo yum -y install mod_wsgi
動作確認用の WSGI アプリケーションを用意する。 このアプリケーションは HTTP のアクセスがあるとそれを処理したプロセス ID を出力する。 ちなみに mod_wsgi は、後述する設定ファイルで指定した .py または .wsgi ファイルの中にある 'application' というシンボルを WSGI アプリケーションとして認識する。
$ cat << EOF | sudo tee /var/www/cgi-bin/myapp.wsgi > /dev/null # -*- coding: utf-8 -*- import os def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) pid = os.getpid() msg = b'Process ID: {pid}\n'.format(pid=pid) return [msg] EOF
mod_wsgi を組み込みモードで動作させる
まずは mod_wsgi を組み込みモードで動作させてみよう。 mod_wsgi はデフォルトで組み込みモードで動作する。 そのため設定はとてもシンプルで WSGIScriptAlias にデプロイ先と WSGI アプリケーションのパスを渡すだけで良い。
$ cat << EOF | sudo tee /etc/httpd/conf.d/wsgi.conf > /dev/null WSGIScriptAlias /myapp /var/www/cgi-bin/myapp.wsgi EOF
Apache httpd を起動する。
$ sudo systemctl start httpd
$ sudo systemctl enable httpd
WSGI アプリケーションに curl コマンドでアクセスしてみよう。
$ curl http://localhost/myapp Process ID: 15950 $ curl http://localhost/myapp Process ID: 15953 $ curl http://localhost/myapp Process ID: 15952
どうやら毎回リクエストを処理しているプロセス ID が異なるようだ。
上記のプロセス ID は Apache httpd のそれと同じになっている。 そう、つまり組み込みモードでは Apache httpd が静的ファイルなどを処理するのと同じプロセスが WSGI アプリケーションも処理することになっている。 今の Apache httpd はデフォルトではマルチプロセス (prefork) で動作するため、その場合は必然的に WSGI アプリケーションもマルチプロセスとなる。
$ ps auxww | grep [h]ttpd root 15949 0.0 0.5 217144 5404 ? Ss 12:27 0:00 /usr/sbin/http -DFOREGROUND apache 15950 0.0 0.7 220352 7964 ? S 12:27 0:00 /usr/sbin/http -DFOREGROUND apache 15951 0.0 0.6 219188 6168 ? S 12:27 0:00 /usr/sbin/http -DFOREGROUND apache 15952 0.0 0.7 220352 7964 ? S 12:27 0:00 /usr/sbin/http -DFOREGROUND apache 15953 0.0 0.7 220352 7964 ? S 12:27 0:00 /usr/sbin/http -DFOREGROUND apache 15954 0.0 0.6 219188 6168 ? S 12:27 0:00 /usr/sbin/http -DFOREGROUND
mod_wsgi をデーモンモードで動作させる
次はデーモンモードで動かしてみる。 先ほどの組み込みモードでは Apache httpd が静的ファイルを処理するのと同じプロセスで WSGI アプリケーションを処理していた。 それに対し、デーモンモードでは WSGI アプリケーションを処理するために専用のプロセスが新たに用意される。 つまり、デーモンモードでは WSGI アプリケーションへのリクエストがあった場合に Apache httpd のフロントエンドのプロセス達がデーモンプロセスに対する Proxy のように動作するイメージだ。
デーモンモードで動かす場合の設定は先ほどより多少多くなる。 WSGISocketPrefix はフロントエンドのプロセスとデーモンプロセスが通信するための UNIX ドメインソケットの場所を設定している。 これは明示的に設定しなくても問題ない場合もあるようだ。 WSGIDaemonProcess はデーモンプロセスの設定を担っている。 デーモンプロセスはデフォルトでは 1 プロセス 15 スレッドの状態で用意される。 そして、Location ディレクティブを使って動作する場所を指定した上で WSGIProcessGroup で使用するデーモンプロセスを指定する。
$ cat << EOF | sudo tee /etc/httpd/conf.d/wsgi.conf > /dev/null WSGISocketPrefix /var/run/wsgi WSGIDaemonProcess myapp-process WSGIScriptAlias /myapp /var/www/cgi-bin/myapp.wsgi <Location /myapp> WSGIProcessGroup myapp-process </Location> EOF
設定できたら Apache httpd を再起動しよう。
$ sudo systemctl restart httpd
先ほどと同様に curl で WSGI アプリケーションにアクセスしてみる。
$ curl http://localhost/myapp Process ID: 16175 $ curl http://localhost/myapp Process ID: 16175 $ curl http://localhost/myapp Process ID: 16175
今度は全てのリクエストが同一プロセスで処理されていることがわかる。
まとめ
今回は mod_wsgi の二つの動作モード、組み込みモードとデーモンモードを動かしてみた。 組み込みモードでは、設定する項目が少ない反面チューニングの余地も少なく、必然的にマルチプロセスになってしまう点に注意が必要といえる。 特にマルチプロセスに関しては、WSGI アプリケーションをマルチプロセスで適切に動作するようにあらかじめ想定した上で作っていないと問題となる可能性が高い。 それに対し、デーモンモードであればプロセス数やスレッド数を任意の値に設定できる。 また、mod_wsgi を動作させる場合のデフォルトが組み込みモードとなっているのは、そちらが推奨されているためではなく後方互換性を保つためという理由のようだ。 以上の理由から、特に理由がないのであれば mod_wsgi はデーモンモードを使って動かした方が無難なようだ。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る