Apacheのmod_cgiとmod_cgidとpreforkとevent。

自分用メモ。

  • mod_cgi
    Unix でマルチスレッドの MPM を使っている場合は、このモジュールの 代わりに mod_cgid を使う必要があります。 ユーザレベルではこの二つのモジュールは本質的には同一です。
  • mod_cgid
    Unix オペレーティングシステムの中には、マルチスレッドのサーバから プロセスを fork するのが非常にコストの高い動作になっているものがあります。 理由は、新しいプロセスが親プロセスのスレッドすべてを複製するからです。 各 CGI 起動時にこのコストがかかるのを防ぐために、mod_cgid は子プロセスを fork して CGI スクリプトを実行するための 外部デーモンを実行します。 主サーバは unix ドメインソケットを使ってこのデーモンと通信します。

    コンパイル時にマルチスレッド MPM が選ばれたときは mod_cgi の代わりに必ずこのモジュールが使用されます。 ユーザのレベルではこのモジュールの設定と動作は mod_cgi とまったく同じです。唯一の例外は ScriptSock ディレクティブの 追加で、このディレクティブは CGI デーモンとの通信用のソケットの名前を 指定します。
  • prefork
    このマルチプロセッシングモジュール (MPM) は、 Unix 上での Apache 1.3 のデフォルトの挙動と非常によく似た方法で リクエストを処理する、スレッドを使わず、先行して fork を行なう ウェブサーバを実装しています。 スレッドセーフでないライブラリとの互換性をとるために、 スレッドを避ける必要のあるサイトでは、このモジュールの使用が適切でしょう。 あるリクエストで発生した問題が他のリクエストに影響しないように、 個々のリクエストを単離するのにも、最適な MPM です。
  • event
    The event Multi-Processing Module (MPM) is designed to allow more requests to be served simultaneously by passing off some processing work to the listeners threads, freeing up the worker threads to serve new requests.

    event is based on the worker MPM, which implements a hybrid multi-process multi-threaded server. A single control process (the parent) is responsible for launching child processes. Each child process creates a fixed number of server threads as specified in the ThreadsPerChild directive, as well as a listener thread which listens for connections and passes them to a worker thread for processing when they arrive.

    event マルチプロセッシングモジュール(MPM)は、処理動作のいくつかをリスナースレッドに受け渡し、新しいリクエストを扱うためにワーカースレッドを開放することによって、より多くのリクエストを同時に受け入れるように設計されている。
    event は、マルチプロセスとマルチスレッドのハイブリッドサーバである worker MPM をベースとしている。一つのコントロールプロセス(親)が子プロセスの起動を行う。それぞれの子プロセスは ThreadPerChild ディレクティブで指定された固定数のサーバスレッドを、接続を待ち受けてそれを処理するためにワーカースレッドに受け渡す一つのリスナースレッドと同時に生成する。
  • worker
    このマルチプロセッシングモジュール (MPM) は、マルチスレッドとマルチプロセスのハイブリッド型サーバを 実装しています。リクエストの応答にスレッドを使うと、 プロセスベースのサーバよりも少ないシステム資源で、 多くのリクエストに応答することができます。 それにもかかわらず、多くのスレッドを持った複数のプロセスを 維持することで、 プロセスベースのサーバの持つ安定性も保持しています。
というようなことをまとめてみると、prefork はマルチプロセス、event と worker はマルチプロセス/マルチスレッドということになります。スレッドセーフじゃない CGI は prefork のほうがいい、でも prefork はリソースを食うから、スケーラビリティが重要ならスレッドセーフにして event か worker を使う、という感じでしょうか。
一方でこういう記事を見つけました。
ApacheでCGIを使う場合にpreforkを使った方が良い状況とそのチューニングについて。ここでは mod_cgid がシングルプロセスであるため、そこがボトルネックになってリクエストを取りこぼす状況がありうるということが示唆されています。一方 mod_cgi はリクエストごとに個別にプロセスを起動するため、マルチスレッドではないがマルチプロセスが有効に働いてかなりいい数値を出してきています。もちろんこれは PC のコア数、アプリケーションの処理内容とか DB へのアクセスなどの複合要因で変わってくるとは思いますが、シナリオによっては prefork のほうがよい場合がある、ということを示唆しています。

(以下の表は作成中に付き嘘がいっぱいかもしれない)

MPM 実装 CGI FastCGI Perl Python PHP
prefork マルチプロセス mod_cgi mod_fcgi mod_cgi
mod_fcgi
mod_proxy_uwsgi mod_php
worker マルチプロセス
マルチスレッド
mod_cgid mod_proxy_uwsgi php_fpm
event マルチプロセス
マルチスレッド
mod_cgid mod_proxy_fcgi mod_proxy_uwsgi php_fpm
ちょっと分かりづらいので、もうちょっと分類してみようと思います。
  • mod_cgi
    prefork の場合には mod_cgi が使われる。
  • mod_cgid
    event および worker の場合には mod_cgid が使われる。ScriptSock ディレクティブが追加されていて、UNIX ソケットを扱える。
  • mod_mime
    AddHandlerは mod_mime がサポートしている。
  • mod_alias
    ScriptAliasは mod_alias がサポートしている。
  • mod_proxy
    Apache は他の CG Iへのインタフェースのために PROXY モジュールを利用する。ProxyPassは mod_proxy がサポートしている。
  • mod_proxy_fcgi
  • mod_proxy_scgi
  • mod_proxy_uwsgi
  • uWSGI Perl support (PSGI)
    PSGI とカッコ書きで書いてあるとおり、PSGI へのインタフェースを提供するもの。つまり Plack のようなミドルウェアが必要となるし、PSGI daemon(もしくはサーバ)が必要となる。
  • Running PHP scripts in uWSGI
  • Running CGI scripts on uWSGI
    これは CGI 実行のためのサーバなどを必要としないので、イメージとしては uWSGI が CGI プログラムを実行してそれを ポートあるいはソケット経由で Apache や Nginx に提供する形になる。mod_cgi を mod_cgid + uWSGI with CGI plugin で置き換える感じ。
  • PSGI/Plack
  • Perl CGI
  • mod_http2
    MPM Configurationによれば、prefork では mod_http2 はたった一つのコネクションしか扱えないためにサーバがストールするため、ベストな選択は event を使うこと。
  • ProxyPass ディレクティブ
  • mod_wsgi
  • mod_fcgid
    リポジトリを見ると、2.3.9(最新版)がリリースされたのは2013年10月。Apache 2.5 のドキュメントは用意されているようだが、メンテナンスされているのかどうかは不明。fcgi + mod_proxy_fcgid のほうがよいかも。

こうしてピックアップしてみると、Webアプリケーションをサーバで動かすにはいろいろと方法があって、どれが最適化はそのアプリケーション(あるいは言語やプラットフォーム)によるし、唯一無二のベストなソリューションはない、というか、ないからこそいろいろな方法があるんでしょうね。

CGI でふと思い出したけれど、Wikiエンジンで一番最初に触れた TWiki は Perl で動かしていたのでした。

Perl 関連:
(作成中)
CGI::Alternativesによれば、
(他の言語でもそうだけれど)コード中に html コードを組み込むのではなく、Perl コードと HTML コードを分離してテンプレート化して利用するほうがよい。CGI.pm は 5.22 以降ではすでに core から外されて、標準ライブラリではなくなっている。コードとHTMLを切り離すテンプレート方式を強く推奨するし、新規で開発するなら MojoliciosDancer2CatalystあるいはPSGI/Plackを使うべき。常に使われるような軽めのアプリケーションなら Mojolicios か Dancer2 を、大きいアプリケーションなら Catalyst を検討したほうがよい。
という感じ。
Plack/PSGI のインストールは Handbook を参考に。
太古のCGIプログラム
CGIプログラム
CGI::Fastプログラム
Plackプログラム

(余談)
Manjaro では Plack のパッケージがなかったため、CPAN からインストールしたらぞろぞろとたくさんのパッケージがインストールされた。
Apache-LogFormat-Compiler-0.35-0  File-ShareDir-1.116-0         LWP-MediaTypes-6.04-0           Test-LeakTrace-0.16-0
Class-Inspector-1.34-0            File-ShareDir-Install-0.13-0  List-MoreUtils-0.428-0          Test-MockTime-0.17-0
Cookie-Baker-0.10-0               Filesys-Notify-Simple-0.13-0  List-MoreUtils-XS-0.428-0       Test-Requires-0.10-0
Cpanel-JSON-XS-4.11-0             HTTP-Date-6.02-0              Module-Build-0.4229-0           Test-SharedFork-0.35-0
Devel-StackTrace-2.03-0           HTTP-Entity-Parser-0.21-0     Module-Build-Tiny-0.039-0       Test-TCP-2.19-0
Devel-StackTrace-AsHTML-0.15-0    HTTP-Headers-Fast-0.22-0      POSIX-strftime-Compiler-0.42-0  Test-Time-0.07-0
Encode-Locale-1.05-0              HTTP-Message-6.18-0           Params-Util-1.07-0              Test-Warnings-0.026-0
Exporter-Tiny-1.002001-0          HTTP-MultiPartParser-0.02-0   Plack-1.0047-0                  Try-Tiny-0.30-0
ExtUtils-Config-0.008-0           Hash-MultiValue-0.16-0        Stream-Buffered-0.03-0          WWW-Form-UrlEncoded-0.25-0
ExtUtils-Helpers-0.026-0          IO-HTML-1.001-0               Test-Deep-1.128-0
ExtUtils-InstallPaths-0.012-0     JSON-MaybeXS-1.004000-0       Test-Fatal-0.014-0

Apache で FastCGI アプリケーションを動作させる方法は現実的には二通りで、mod_fcgid を使って Apache にサーブさせる方法と、mod_proxy_fcgi を使って他の FastCGI サーバへの proxy をさせる方法がありますが、mod_fcgid はApache のパッケージには含まれていないため今後どうなるかが不明なのと mod_fcgid 自体がパフォーマンスを優先するためかリソースをどか食いするらしいこと、どうやら時代の流れ的には uWSGI にしても PSGI にしてもそうですがアプリケーションの管理は外部のサーバに任せて、Apache 自体は PROXY を通して利用する、という方向なのかなという感じ。Perl の場合には Plack を使うか、fcgiwrap + spawn-fcgi でサーブさせるか、の二通りがありそうです。
spawn-fcgi は lighttpd に含まれているようです。


Python 関連:
(作成中)
uWSGI
GNU Mailmanは、Mailman 2.1 は Python 2.7 でかつ CGI/1.1 API が必要、Mailman 3 は Python 3.4 以降で WSGI が必要、ということなので、もしかして Django ベースのアプリを使わないなら CGI あるいは FastCGI で十分に足りてしまいそうな予感。というかそれがベストかもしれません。

PHP 関連:
(作成中)
PHP で使うアプリは今のところ WordPress のみなので、php-fpm を使って FastCGI で構築すればよさそうです。

ということは、Perl も含めて、Apache の FastCGI(mod_proxy_fcgi) で全部扱えそうな感じです。

0 件のコメント:

コメントを投稿

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。  busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv...