PHP における「モジュール版」と「CGI 版」の比較 + WordPress の適用例
PHP のパフォーマンスを調べる中で「モジュール版」と「CGI版」という言葉をみつけまして、本エントリーではそれぞれの内容、およびパフォーマンス・セキュリティ等の観点で両者を比較してみました。
併せて、PHP プログラムである WordPress を適用した場合について示しています。
Web サーバは Apache を対象にしています。内容について認識誤り等ありましたらご指摘ください。
1.用語
まず最初に「CGI版」と「モジュール版」の意味について記します。
[CGI 版]
「CGI」は「Common Gateway Interface」の略で、サーバが受信したブラウザの要求に応じてプログラムを起動するための仕組みを指します。PHP の場合、ブラウザに
http://?/xxx.php
を URL として指定した場合、Webサーバは xxx.php を実行ファイルと認識してプログラムを起動し、その実行結果を返却します。これを「CGI 版」と言うようです。
[モジュール版]
「モジュール」とは、Apache の機能を拡張するための「部品」(と考えるのが分かりやすそうです)。PHP もこのモジュールを利用することで Apache の一機能として PHP を動作させることができます。
つまり「モジュール版」とは、この Apache の拡張モジュールを利用していることを指すようです。
下記のサイトの「補足2 モジュールとは」にモジュールのイメージが掲載されています。
PHP5 + Apache(Windows)の httpd.conf の設定に着目した場合、下記の違いがあります。
CGI 版として利用する場合の設定
ScriptAlias /php/ "c:/php/"
AddType application/x-httpd-php .php
Action application/x-httpd-php "/php/php-cgi.exe"
モジュール版として利用する場合の設定
LoadModule php5_module "c:/php/php5apache2.dll"
AddType application/x-httpd-php .php
PHPIniDir "C:/php"
PHP の MIME タイプはいずれも AddType ディレクティブで、.php という拡張子を指定されたコンテントタイプ application/x-httpd-php にマップしていますが、CGI 版は Action ディレクティブで CGI を実行するように設定、モジュール版は LoadModule ディレクティブにより、ライブラリ php5apache2.dll を Apache のが利用可能なモジュール php5_module として追加しています。
2.パフォーマンスによる比較
PHP 公式サイトのトップページに次のような記述があります。
日本 PHP ユーザ会:PHPについて
通常のCGIとして使用できますが、PHPモジュールをApacheサーバーに組み込むことにより、 Perl/CGIと比較して処理速度の高速化、サーバー負荷の低減が可能です。
明らかに「CGI 版」より「モジュール版」のパフォーマンスが上回っているようです。
1項の説明で「CGI 版」「モジュール版」いずれも PHP プログラムを起動することには違いないのですが、モジュール版 のパフォーマンスが良いのは下記の違いによるようです。
- CGI 版:PHPプログラムが呼び出されるたびにプロセスが1つ立ち上がる
- モジュール版:Apacheのプロセスの中で実行されるため、余分なプロセスを立ち上げる必要がない
プロセスの説明は省略しますが、下記の記事の「仕組みはどうなっているのか」に分かりやすい説明があります。
ということで、パフォーマンス面では「モジュール版」が断然有利で、WordPress でもモジュール版の利用がお勧めです。
3.セキュリティによる比較
共有レンタルサーバの PHP モジュール版には「セーフモード」と呼ばれる設定が施されています。
「セーフモード」とは、共有サーバでのセキュリティの問題を解決するための仕組みで、例えば、同一サーバの他のユーザが自ユーザのファイルを参照できないようにすることができます。
この制限により、例えば WordPress では、ブラウザの管理画面でファイル操作を行う場合等に影響があるようです。これはブラウザから実行した時のユーザ ID がサーバ上のユーザ ID と異なるためで、この操作がセーフモードにひっかかってしまうようです。
CGI 版の場合、「suEXEC」という機能を利用します。これは Apache で Web サーバを実行しているユーザ ID とは 異なるユーザ ID(それぞれのコンテンツユーザーの権限)で CGI プログラムや SSI プログラムを実行する機能です。これによりセキュリティを確保しているようです。
Xrea(エクスリア) は PHP モジュール版が利用できるレンタルサーバですが、セーフモードが設定されています。上記の影響を回避するには特定の機能を CGI 版として利用します。
不具合を回避する方法の詳細等につきましては下記のリンクを参照ください。
- Numb.:XREA で WordPress のファイルアップロード機能を CGI として動かす
- PHP小屋:PHPスクリプト設置者のための豆知識
- hiromasa.zone :o):セーフモードの束縛
- Wordpress ME 2.0 - Docs:キャッシュ機能の利用(セーフモードでキャッシュ機能を利用する場合の設定)
4.レンタルサーバで CGI 版が利用される理由
上記までの比較では、ユーザの立場としては「モジュール版」の利用が有利ですが、さくらインターネット等のレンタルサーバで CGI 版が提供されているのは、ひとつには下記の理由があるようです。
DreamHostのカタチ ?良い鯖.com?:PHP について
Apache module版だと、Dreamhost管理人がユーザごとの PHP 負荷を計測するのが不可能なのが原因
つまり、共有レンタルサーバ運営サイドとしては、メンテナンス面でCGI 版が勝っているのではないかと考えます。この辺りは詳細な調査ができておりませんので私の推測が間違っているかもしれませんし、逆に正確な情報を頂ければという思惑も含んでいます。
5.まとめ
項目は色々あると思いますが、とりあえず上記までの内容とその他思いついた項目でまとめてみました。
| 項目 | CGI 版 | モジュール版(Apache モジュール) |
|---|---|---|
| 実行プロセス | PHP のプロセス | Apache のプロセス |
| レスポンス | 遅い | 速い |
| サーバ負荷 | 多い | 少ない |
| セキュリティ | suExec | セーフモード |
| ファイルのパーミッション | 775/777等 | 604等 |
| メンテナンス | 負荷計測が不可能? | |
| その他 | システム系などの一部の関数が使用不可 |
6.CGI 版からモジュール版に乗り換えた例
最近では、WordPress ユーザの caramel*vanilla さんが、さくらのレンタルサーバ(CGI 版)から XREA+(モジュール版)に乗り換えられました。多発していた 503 エラーが解消され、アクセスも快適になっています。
7.その他
未整理の関連リンクです。
- XREA SUPPORT BOARD:public_html内のPHPのモジュール化
- PHP5.0/2.Apache2の設定
- MIME Media Types
- Apache 2.0 モジュール一覧
- PHPのインストール(Apache2.0 Linux編)
- PHP マニュアル
- PHP マニュアル:Apache 2.0 (Unixシステム用)
Apache のチューニング(その3)・DiceによるWindows再起動
Apache の再起動を周期的に行うことでメモリリークを回避する設定にしていますが、その2でお伝えした通り、再起動が正常に行われなかった場合、エラーが発生します。さらに Apache のプロセスが残る場合もあるようで(しかもそのプロセスが数十MBのメモリを喰ったまま)、あまりいい按配ではありません。
ということで Apache の方は現在の設定にして、Windows の再起動を行う方法を追加することにしました。Windows のタスクスケジューラで再起動できるようですが、Dice にプログラムスケジューラー機能があり、この中にシャットダウンや再起動も組み込まれていることを知りましたので、これを使って1日1回再起動を行ってみることにしました。以下 Windows XP での設定方法です。
これだけでは再起動時のログインパスワード入力で止まってしますので Windows 再起動時にパスワード入力を不要にする設定を実施します。
「スタート」→「ファイル名を指定して実行」を選択して、
- control userpasswords2
を入力して実行します。ユーザーアカウント画面が開くので「ユーザーがこのコンピュータを使うには、ユーザー名とパスワードの入力が必要」のチェックを外して「OK」をクリックします。その後自動ログオンの設定画面が開くので、ログオンする時のユーザー名とパスワードを設定して「OK」をクリックします。
参考サイトは下記です。ありがとうございました。
Apache のチューニング(その2)
先日、その1で MaxRequestsPerChild でリクエスト数の上限を設定し、子プロセスを再起動するようにしましたが、下記のエラーが時々発生しています。
[crit] [Mon Nov dd hh:mm:ss 2005] file .\\server\\mpm\\winnt\\child.c, line 1060, assertion "(rv >= 0) && (rv < threads_created)" failed
ネットで同様の事象を検索したところ、下記の1件しかヒットしませんでした。
対処は「バージョンを 2.1.8 にアップグレードする」と書かれています。Apache HTTP Server は現在 2.1.9-beta がリリースされていますが、Windows 版は 2.0.55 が最新のため、残念ながらこのエラーは回避できないようです。
Apache のチューニング(その1)
先日より続いているアクセス不具合についてチューニング(というほどのものではありませんが)を実施しました。何回か報告する機会がありそうなのでとりあえず「その1」に。
不具合に関連する事象で把握できているのは次の3点です。
- Apache プロセスのメモリが増加し続け(メモリリーク)、1日で数百MBに膨れ上がる
- 何らかの契機にレスポンスが突然遅くなる(お昼休み等、アクセスが集中すると×?)
- Apache を再起動すればアクセスは正常になる
チューニング関連の記事を調べた結果、下記の2つのディレクティブについて httpd.conf に設定することにしました。
MaxRequestsPerChild
これは個々の子サーバが稼働中に扱うリクエスト数の上限で、このディレクティブに設定された値を超えると子プロセスは終了(再起動)します。デフォルトは 0(=子プロセスを終了しない)ですが、現在は 5000 に設定しています。記事によっては2桁?3桁で書かれているものもあり、どの程度の値にすればよいか悩みましたが、やや大きめの値にしています。
この設定で1日稼動させてみたところ、レスポンスが遅くなるという事象は収まったようです。ただログを確認するとプロセス再起動の周期がやや短いようなので、値の調節はもう少し必要かもしれません。
参考記事は下記です。
- MaxRequestsPerChild ディレクティブ
- PHP-users:Apacheのメモリー使用量について
- @IT:Apacheパフォーマンス・チューニングの実践
- CGI Laboratory:WindowsでApacheを使うには?
Win32DisableAcceptEx
もうひとつのディレクティブ Win32DisableAcceptEx は上記の検索をしている時にたまたまみつけたもので、Windows の winsock が原因で AcceptEx のエラー
指定されたネットワーク名は利用できません。 : winnt_accept: Asynchronous AcceptEx failed.
セマフォがタイムアウトしました。 : winnt_accept: Asynchronous AcceptEx failed.
が頻繁に発生するようです。VirtualHost 別のエラーログばかり見ていたので気がつかなかったのですが全体のエラーログに上記のエラーがかなり大量に頻繁に発生していました。
アクセス不具合との関連がないにしてもこれは回避しておきたいので、MPM_WinNT モジュール部分に Win32DisableAcceptEx を追加。これで上記のメッセージは止まりました。
参考記事は下記です。
まとめ
現在の httpd.conf の(該当箇所の)設定は次のようになっています。
<IfModule mpm_winnt.c>
ThreadsPerChild 250
MaxRequestsPerChild 05000
Win32DisableAcceptEx
</IfModule>
MaxRequestsPerChild はデフォルト値 0 を書き換え、Win32DisableAcceptEx は1行追加。ThreadsPerChild はデフォルトで設定された値をそのまま利用しています。
また上記と併せてPHPやCGIエラー等もエラーログを参照しながら除去しました。

