Apache2.4 を event MPM + FastCGI で動かす

プロセスベースの並列実行をする prefork を使用していたのですが、省メモリのためにスレッドベースの並列実行をする event へ変更します。
構成としては、Apache2.4 + event + mod_proxy_fcgi + php-fpm です。 それぞれの MPM の特徴に関しては、以前書いたこちらの記事で簡単に紹介しています。 norikone.hatenablog.com

動きを確認するためにそれぞれデフォルトの設定で、PHPプログラムが動いているサーバに簡単な負荷テストを行ってみたところ、プロセスを多数起動しない分やはり event の方が使用メモリ量が少ないという結果が出ました。
スループットも若干 event が prefork を上回る結果になりました。

ただ、速度に関しては配信するコンテンツの内容やリクエスト数によって prefork が上回るケースも十分考えられるので、環境ごとに検討する必要があるかと思います。

event で動かすために必要なものと背景

prefork を選択している場合には、ApachePHP の連携の定番である mod_php を使用することができました。
しかし、event を選択した場合には PHP の実行を mod_php に任せることができません。
というのも、mod_php がスレッドセーフではないためです。

prefork では、Apache がリクエストごとにプロセスを生成するため、メモリ空間上で競合が生じません。
event では、リクエストごとにスレッドを生成して処理するので、メモリ空間を共有していまい競合が生じてしまいます。
そのため、スレッドセーフな環境で実行してあげる必要があります。

そこで、 PHP 処理は php-fpm に任せることにします。
mod_php の場合、Apache が生成する各 httpd プロセスに PHPインタプリタを埋め込んでそのプロセス内で PHP を処理していたので結びつきが強かったのですが、php-fpm の場合 Apache とは分離された存在になっています。
その辺りはこちらの図が分かりやすいです。
  f:id:norikone:20160207044201p:plain  
f:id:norikone:20160207044159p:plain (参照 : http://z-issue.com/wp/apache-2-4-the-event-mpm-php-via-mod_proxy_fcgi-and-php-fpm-with-vhosts/)

一枚目が prefork + mod_php 構成の図で、二枚目が event + php-fpm + mod_proxy_fcgi 構成の図です。
二枚目では、スレッドがリクエストを受け付けて、mod_proxy_fcgi というモジュールを介して php-fpm に PHP の実行を依頼する、という流れです。
静的ファイル等は Apache が、PHPphp-fpm が、という形になります。

ということで前置きが長くなりましたが、php-fpm と mod_proxy_fcgi があれば event で動かすことが出来るようになるので、設定していきます。
環境は Amazon Linux AMI , Apache2.4 です。

php-fpm インストール

まずは PHP プログラムを処理するための php-fpm をインストールします。

yum install php56-fpm

起動します。

service php-fpm start

自動起動をONにします。

chkconfig php-fpm on

これで php-fpm の準備はできました。
特に設定を変更していなければ、9000番ポートでリクエストを待ち受けるようになります。

mod_proxy_fcgi を有効にする

Apache が起動したスレッドと php-fpm の仲介をするモジュールの設定をします。
mod_proxy_fcgi を有効にすることで、ApacheFastCGI プロトコルを使用して外部の PHP 処理系にリクエストを渡すことが出来るようになります。
また、mod_proxy_fcgi が動作するためには、mod_proxy が必要です。

恐らくデフォルトで有効になっていますが、/etc/httpd/conf.modules.d/00-proxy.conf の以下の行がコメントアウトされていないか念のため確認しておきます。

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

次に、仮想ホストファイルなどを編集してプロキシの設定をします。
以下の行を追記するだけです。

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9000/"
</FilesMatch>

例として、こんな感じになります。

<VirtualHost *:80>
    DocumentRoot "/var/www/html/public"
    ServerName hoge.com
    <Directory "/var/www/html/public">
        <FilesMatch \.php$>
            SetHandler "proxy:fcgi://127.0.0.1:9000/"
        </FilesMatch>
    </Directory>
</VirtualHost>

これで、mod_proxy_fcgi を通して php ファイルの実行を php-fpm に委任する設定が完了しました。

MPM を event に切り替える

event の動作に必要な環境は整いました。
実際に MPM を切り替えてみます。

/etc/httpd/conf.modules.d/00-mpm.conf で prefork をロードしている箇所を event をロードするよう修正します。
Apache2.3 からは MPM は LoadModule ディレクティブで動的に選択することが可能になっています。

# LoadModule mpm_prefork_module modules/mod_mpm_prefork.so #コメントアウト
~
LoadModule mpm_event_module modules/mod_mpm_event.so #コメントアウト削除

これだけで event へ切り替えることが出来ます。
あとは、/etc/httpd/conf.modules/01-cgi.conf 等をいじって使用しないモジュールをロードしないようにしておきましょう。

確認

httpd -M

で、 mpm_event_module (shared) が表示されていれば event が選択された状態になっています。
また、phpinfo で FastCGI で動作しているか確認できます。
f:id:norikone:20160207213201p:plain prefork + mod_php で動作している場合は、ここに「Apache handler 2.0」と表示されるので、変更できていることが分かります。