2007-09-03

spawn-fcgiで標準入出力用FastCGIサービスを独立プロセス化する

Rails含め、多くの場合 FastCGIはCGIの延長線上にある使われ方をする。つまりWebサーバによってforkされ、リダイレクトされた標準入出力を使ってサービスを提供する。この時、プロセスのライフサイクルは Webサーバによって管理される。ただのCGIと違うところは、いちどforkされたプロセスが再利用されることである。これによって fork/execのオーバーヘッドが除かれ、結果として "Fast"が実現する。

一般的な FastCGIに対する認識はここまでに尽きることが多い。

だが、FastCGIはWebサーバと切り離され独立したプロセスとして立ち上げることも出来る。その場合、Webサーバとの通信には TCP又は UNIX Domain Socket(名前付きパイプ)が使われる。この通信のために FastCGIプロトコルというれっきとした通信プロトコルが存在する。
(実際には、WebサーバからforkされるタイプのFastCGIアプリケーションも内部的にはこのプロトコルでWebサーバと通信しているのだが)

独立したプロセスとして構築された FastCGIサービスには次のようなメリットがある。
・任意のユーザ権限によるサービスの提供が可能
・リクエストの同時処理をマルチスレッドで実現できる
・Webサーバと別のホストでサービスを動作させることでリソースの分散が可能(TCPの場合のみ)

しかし、このタイプのFastCGIアプリケーションを開発するには CGIの延長線上よりは若干ローレベルな APIを駆使する必要があり、既存の(標準入出力をベースとした)コードを対応させるのは難しい。

いつものごとく前置きが長くなったが、spawn-fcgiは標準入出力ベースで作成された FastCGIアプリケーションを独立プロセス型に変換するラッパーである。spawn-fcgiは lighttpdのオマケとして収録されている。

$ spawn-fcgi -f myfcgiapp.fcgi -p 8000

上記コマンドで、(Apacheなりlighttpdなりから forkされる前提で作られた)mycfgiapp.fcgiを TCPポート8000番で待ち受けるデーモンとして起動させることが出来る。

他の主なオプションは下記のとおり。
-s <path> ...UNIXドメインソケットの指定
-P <path> ...デーモン化したfastcgiプロセスのPIDを記録するファイル
-n ... forkしない(プロセスをバックグラウンド化しない)
-c <dir> ...chroot環境で実行(root権限でspawn-fcgiを実行する場合のみ)
-u <user> ...指定したユーザの権限でサービスを実行(同上)
-g <group> ...指定したグループの権限でサービスを実行(同上)

Railsの dispatcher.fcgiも spawn-fcgi経由で独立プロセス化できる。そのためのスクリプトscript/process/spawnerが用意されている。

注意したいのは、spawn-fcgiで独立プロセス化された FastCGIアプリケーションはシングルプロセスシングルスレッドなので、それ単体ではリクエストの同時処理ができないことだ。Railsのspawnerは spawn-fcgiを別々のポート番号で複数起動することで多重化入出力に対応しようとするが、Webサーバ側をそれに対応させるためには適切にロードバランス設定をしてやる必要がある。lighttpdならきっと出来るんだろうし、Apache2.2でもmod_proxy_fcgiとProxyロードバランス機能の組み合わせで出来るだろう。たくさん同時実行させようとすると、多分すごく面倒だろうけど。

いずれにせよ、最もスループットの高いFastCGIアプリケーションを構築するには FastCGIのローレベルなAPIを使ってマルチスレッドでリクエストを処理するようなプラットフォームが必要であり、spawn-fcgiはそれに対応できるまでの代替措置でしかない。Railsに関しては単独でマルチスレッドの FastCGIサービスとして動作出来るようになるのが理想だが、これは ruby-fcgiがローレベルなFastCGI APIを Pure Rubyでしか現状では提供していないことや、もともと Railsがマルチスレッド対応でないことなどから実現するとしても随分先になりそうだ。

0 件のコメント:

コメントを投稿

<< ホーム