FastCGIとは、CGIプロセスの起動と終了にかかる手間を減らすことにより、プログラムをCGIで高速に動作させるとともに、サーバーへの負荷も少なくすることができる仕組みです。Apache httpd での FastCGI の実装 mod_fcgid により PHP を動作させると、mod_php と同じようなパフォーマンスで PHP を実行できるそうです。そこで今回は、mod_fcgid を使って FastCGI PHP を設定し、mod_php とのパフォーマンスを比較してみました。
環境
サーバーOSは CentOS7.3 (1611) です。Apache httpd 2.4 と PHP 7.1 を yum でインストールしています。
FastCGI PHP の設定
FastCGIモジュール「mod_fcgid」のインストール
Apache httpd の FastCGIモジュール「mod_fcgid」をインストールします。
サードパーティから提供されていた FastCGIモジュール「mod_fastcgi」は、2017年9月14日現在、提供元の www.fastcgi.com のサイトに接続できなくなっています。有志の方(?)がアーカイブサイトを立ち上げていますが、今後のメンテナンスがどうなるかは不明なため、現時点では Apache httpd で FastCGI を使うには「mod_fcgid」一択になりそうです。
php-cgi のラッパースクリプトの作成
環境変数で FastCGI PHP の動作設定を指定するため php-cgi のラッパースクリプトを作成します。
vi /usr/local/bin/php-wrapper
export PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_CHILDREN=0
exec /usr/bin/php-cgi
export PHP_FCGI_MAX_REQUESTS=10000
FastCGI PHP の最大リクエスト数の設定です。初期値は500リクエストでこの回数を越えるとプロセスを再起動するため、「500 Internal Server Error」が発生することがあります。これを回避するため、PHP_FCGI_MAX_REQUESTS は大きめに設定し、Apache httpd に設定する FcgidMaxRequestsPerProcess にそれよりも小さい値を指定します。
export PHP_FCGI_CHILDREN=0
PHPが起動する子プロセス数の設定ですが、mod_fcgid を使う場合 PHPの子プロセスを効果的に使用できないため「0」を指定して PHPが子プロセスを管理することを無効にします。
exec /usr/bin/php-cgi
exec コマンドに続いて php-cgi の場所をフルパスで指定します。場所は「which php-cgi」で確認できます。
ラッパースクリプトのパーミッション設定
作成したラッパースクリプトのオーナーを、WEBサーバーの実行ユーザー「apache」に変更し実行権限をつけます。パーミッションが正しく設定されていない場合「500 Internal Server Error」が発生します。
chmod u+x /usr/local/bin/php-wrapper
Apache httpd の設定
mod_php を読み込まないようにします。mod_php をロードしている LoadModule〜 の行をコメントアウトしてもよいでしょう。
・Apache httpd 2.4 での設定サンプルです。5行目と9〜11行目が FastCGI の設定です。
vi /etc/httpd/conf/httpd.conf
<VirtualHost *:80> ServerName www.example.com DocumentRoot "/var/www/phpapp" FcgidMaxRequestsPerProcess 5000 <Directory "/var/www/phpapp"> AddHandler fcgid-script .php Options FollowSymLinks ExecCGI FcgidWrapper /usr/local/bin/php-wrapper .php AllowOverride None Require all granted </Directory> ErrorLog logs/error_log CustomLog logs/access_log combined env=!nolog </VirtualHost>
FcgidMaxRequestsPerProcess 5000
FastCGI アプリケーションの最大リクエスト数の設定です。初期値は0(無制限)になっています。ラッパースクリプトで指定した PHP_FCGI_MAX_REQUESTS よりも小さい値を指定します。
AddHandler fcgid-script .php
.php 拡張子のプログラムを FastCGI(mod_fcgid)で動作させるための設定です。
Options FollowSymLinks ExecCGI
CGIが動作するように「ExecCGI」を指定します。
FcgidWrapper /usr/local/bin/php-wrapper .php
.php 拡張子のプログラムを先ほど作成した php-cgi のラッパースクリプト経由で実行するための設定です。
以上で FastCGI PHP の設定完了です。Apache httpd を再起動します。
場合によっては FastCGI PHP のタイムアウト値の調整などが必要になるかもしれません、詳しくは Apache の公式マニュアルをご参照ください。
mod_fcgid - Apache HTTP Server Version 2.5
動作確認
phpinfo関数で PHP の動作状況を出力して、Server API の行に「CGI/FastCGI」と表示されていれば FastCGI で PHP が動作していることが確認できます。
mod_php との比較
Apache httpd で PHP を動作させるにはモジュール版の mod_php がもっとも効率がよく、サーバーへの負荷も少ないと言われています。やはり気になるのは FastCGI PHP のパフォーマンスではないでしょうか?
そこで、実際に稼働している WordPress でつくられた WEBサイト(規模:10万PV/月)を mod_php から FastCGI PHP に変更しレスポンスタイムやサーバーへの負荷の変化を確認してみました。
結論から言うと月間10万PV程度のWEBサイトであれば、mod_php と FastCGI PHP のパフォーマンスにまったく違いはありません。
PHP を FastCGI で動作させるのは危険じゃないの?
PHP を FastCGI で動作させるから危険ということはありません!
2012年「PHP-CGI の query string の処理に脆弱性JVNVU#520827(CVE-2012-1823)」の一騒ぎで、「PHP」と「CGI」というキーワードから FastCGI PHP も危険という間違った印象を持たれてしまっているようですが、そもそもこの脆弱性(CVE-2012-1823)の回避策として FastCGI PHP への移行が推奨されていました。
おわりに
最近の Apache httpd ではマルチスレッド対応の event MPM がデフォルトになっていて、パフォーマンスも良いとされています。しかしmod_php はスレッドセーフではないため prefork MPMでしか使うとこができません。(そこで FastCGI PHP の登場です)prefork MPM は HTTP/2(mod_http2)が動作しないなどの制限もあります。そろそろ event MPM への移行時期なのかもしれませんね。
コメント
いつも参考にさせていただいております。
一つお伺いしたいのですが、
今回の記事内容とphp-fpmを使った構成とは異なると思いますが、それぞれの位置付けと使い分けを理解できておりません。
今度、記事にして頂けますと幸いです。
>hyukawaさん
コメントありがとうございます。
少し時間がかかるかもしれませんが、この記事の内容(mod_fcgid + php-cgi)と php-fpm との違いについてまとめてみますね。