PythonでつくるWebアプリ/Tornado + Gunicorn + Nginx

この1ヶ月、土日の休みを使いTUBELONGERってWebアプリをつくってました。
言語はPython。
Pythonは日本語の取り扱いが若干面倒だったりするけど、書いてて楽なので好き。
以下、PythonでWebアプリをつくるにあたって調べたり分かったりしたことのメモ。

構成

OS:さくらVPS CentOS 5.5
サーバ:Nginx + Gunicorn
データベース:MySQL

当初はGoogle App Engineで開発を進めてたけど、データストアの使い方を調べるのにいちいち時間をとられたり、Cron的な動作に制限があったりといろいろ面倒くさかったので、途中からroot権限のあるサーバでいちから構築する方向に切り替えました。
やっぱりroot権限は自由度が半端じゃないです。
GAEがダメってわけではないです。
むしろ僕の知識が足りなすぎて学習コストが尋常じゃなかったのでまた今度にしました。

Webフレームワークを選ぶ

Pythonには、山のようにフレームワークが存在します。
当初は、Pylonsでつくろうと意気込んでいたのだけど、やればやるほど学ばなければいけないことが増えていくように感じたので、紆余曲折ありつつ途中からTornadoに切り替えました。
他にRubyでいうSinatraに近いFlaskというフレームワークがあってそれも良さそうでした。

Tornadoを選んだ理由は、GAEのwebappに非常に似ていた(当初webappで作成してたアプリの移植が簡単そうだった)こと、ドキュメントが完全に日本語訳されていたことが挙げられます。ただドキュメントがわりと簡素なので、詳細を知りたければソースコードを読まざるを得ないかも。面倒だったけれど、ソースコードはシンプルで読みやすく、勉強になりました。

ちなみにTornadoは、WSGI(WSGIについてはリンク先のWikipediaを参照)で運用してます。TornadoをWSGIで運用することは公に推奨されていないようだけど、いくつか非同期の機能が使えなくなるだけで元々その機能を使う予定がない場合は問題ないだろうというのと、問題があるとしたら速度的なところだろうと思って、FlaskとTornado(WSGI)両方のベンチマークをとって比較したけれど大した差は見られなかったので、まぁいいかという判断です。

Tornado について少々の雑感

Tornadoは、FriendFeedで使われていたフレームワークが元になっていて、シングルスレッド・ノンブロッキングで動作します。
通常シングルスレッドで動作する為、1リクエストの処理が遅いと全体の性能が大きく劣化します。例えばTornadoサーバが1つ動いている場合、1リクエストに1秒かかると全体の性能も1秒に1リクエストしかこなせない程度に劣化します。シングルスレッドなので当たり前ですね。故にTornadoサーバにはHTTP非同期処理の仕組みが備わっていて、負荷の高いであろう処理は別のWEBサーバで行わせて、そのWEBサーバに大してHTTP非同期処理して性能劣化を防いだりするそうな。
面倒だったので、僕はWSGI+gunicorn:geventを選択しました。

他にもTemplate機能や他便利機能が揃ってます。
CSRF対策機能とかMySQLdbのラッパとか便利です。
総合して、Pylonsほど高機能ではないが、web.pyほどシンプルでもない、中間的な立ち位置のフレームワークに感じました。

Gunicorn

サーバは、Gunicornを選びました。
Gunicornは、WSGIを備えたサーバプログラムで、RubyのUnicornを元につくられたプロジェクト。
この上で、Tornadoを動作させています。
理由は、一番使い勝手が良さそうだったから。(ついったー上でNginx+Gunicornがアツイみたいな発言も見かけたのも大きかった)
他にも似たところで、Apache + mod_wsgiuwsgiといったものがあるようです。
ちなみにGunicornは、ワーカーというものをプラグインで選ぶことが出来ます。
今回は、geventというコルーチンベースのものを選択。
内部でlibeventを使っていて、比較的パフォーマンスが良いらしい。
これとNginxを組み合わせて運用してます。

Nginx

Gunicornをバックエンド、Nginxをフロントエンドとして使ってます。
構築する環境が、さくらVPSということでメモリ容量が少々不安だった為、Apacheよりメモリ消費の少なそうなNginxを選んでみた。
Gunicornと連携する設定は、ここを参考にしました。(というかほぼ丸コピペ)

Supervisord

ファイルに何らかの変更を加えた後、その修正を反映するためにGunicornの再起動が必要だったりするのだけど、いちいちPIDを調べてKILLしたりするのが面倒だったので、Supervisordというプロセス管理ツールを導入してみました。
(Gunicornの設定ファイルにこれを追加することで自動再読み込みさせられるのだけど、本番環境でやるのは気が引けた)

Supervisordを使うと、以下のように簡単に稼働状況を確認したり再起動できたりして、なにかと楽できます。
これは、導入して正解でした。

$ supervisorctl  
supervisor> status gunicorn   
gunicorn                         RUNNING    pid 17275, uptime 3 days, 9:21:22  
supervisor> restart gunicorn   
gunicorn: stopped  
gunicorn: started  

まとめ的な雑感

以上、ざっくりとつかってみたフレームワークやそれについての雑感をつらつらと書いてみた。
何かの参考になれば幸いです。
設定ファイルの中身だとかインストールの手順だとかは省いてしまったけど、いずれ隙をみつけてメモりたい。