Nginx+Fastcgi+PHPでサクサク快適サイト構築!
こんにちは、井川です。連日、猛暑続きですね。熱中症には気を付けて、がんばりましょう。
今回は、軽量なWebサーバであるnginxとPHPを組み合わせて使う方法を紹介します。
Webサイトにとって、軽さはとても重要なポイントです。PHPはライトウェイ トな言語でありながらも、symfonyなど最近のフレームワーク次第ではWebサイトが重くなってしまいます。特に、Apacheで多くのリクエストを同時に受け付けると、レスポンスを返さなくなることがあります。こうした場合、キャッシュを使ったり、Key/ValueストアやMongoDBなどNoSQLにしたり、スケールアウトしたりと、様々な対応が考えられます。
しかし、もっと根本的な解決方法はないでしょうか?
WebサーバとしてApacheではなく、nginxとFastcgi-PHPを使ってみましょう(lighttpdなどもありますが…)。ベンチマークでは、Apacheでリクエストを処理できなかったケースも、nginxなら全て処理できました。
実行環境
CentOS 5.5
PHP 5.3.5
Apache 2.2.3
nginx 1.0.4
nginxとは?
nginx(エンジン・エックス)は高性能なWebサーバであり、リバースプロキシ機能も持っています。nginxは2004年に公開されました。フリーのオープンソースであり、BSD系のライセンスで提供されています。Netsraftによると、トップ100万のサイトの6%がnginxを使っています。現在も着実にシェアを伸ばしています。
nginxのインストールと設定
まずは、最新のnginxをダウンロードします(記事執筆時の最新版は1.0.4)。SSLなど必要なモジュールを組み込んでコンパイルしていきます。今後のことも考え、PCREとOpenSSLを組み込んでおきます。そのため、yumでpcre、pcre-devel、openssl、openssl-develを先に入れておきます。
# yum install pcre pcre-devel openssl openssl-devel
そして、nginxのソースコードのディレクトリで以下のコマンドを実行し、nginxをインストールします。
# ./configure --with-pcre --with-http_ssl_module --with-http_dav_module --with-http_flv_module --with-http_perl_module
# make
# make install
後は、サーバ起動時にnginxも起動するように、/etc/rc.local に以下を記述しておきます。
/usr/local/nginx/sbin/nginx
次にnginxの設定を行います。/usr/local/nginx/conf/nginx.confファイルを以下のように編集します。
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
server_tokens off;
root ドキュメントルートへのパス;
index index.html index.php;
access_log logs/access.log main;
error_log logs/error_log;
location / {
try_files $uri /index.php;
}
location ^~ /index.php/ {
try_files $uri /index.php;
}
location ~ \.php($|/) {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
location ~ /\.ht {
deny all;
}
}
}
FastCGIのインストールと設定
FastCGIはCGIを拡張したものです。通常のCGIは処理毎にプロセスを破棄するため、オーバーヘッドが発生し、パフォーマンスの低下につながります。一方で、FastCGIはプロセスをメモリ上に永続化することで、大量の要求も円滑に処理します。
まずは、yumでspawn-fcgiをインストールします(epelからインストール可能です)。epelをレポジトリに追加していない場合は、以下で追加しておきます。
wget http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm
rpm –ivh http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm
spawn-fcgiのインストール
# yum install spawn-fcgi
次に、php-fastcgi起動用のシェルスクリプト(php-fastcgi)を作成し、/etc/rc.d/init.d/php-fastcgi と配置します。シェルスクリプトの詳細はこちらのサイトを参考にしました。
#!/bin/sh
#
# spawn-fcgi Start and stop FastCGI processes
#
# chkconfig: - 80 20
# description: Spawn FastCGI scripts to be used by web servers
# Source function library.
. /etc/rc.d/init.d/functions
RETVAL=0
SPAWNFCGI="/usr/bin/spawn-fcgi"
PHPFCGI="/usr/bin/php-cgi"
FCGIPORT="9000"
FCGIADDR="127.0.0.1"
PHP_FCGI_CHILDREN=5
PHP_FCGI_MAX_REQUESTS=1000
ALLOWED_ENV="PATH USER"
USER=apache
GROUP=apache
PIDFILE=/var/run/phpfcgi.pid
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"
case "$1" in
start)
PHPFCGI_START=$"Starting ${NAME} service: "
echo -n $PHPFCGI_START
# clean environment
E=
for i in $ALLOWED_ENV; do E="$E $i=${!i}"; done
daemon $SPAWNFCGI -a ${FCGIADDR} -p ${FCGIPORT} -u ${USER} -g ${GROUP} -P ${PIDFILE} -C ${PHP_FCGI_CHILDREN} -f ${PHPFCGI}
RETVAL=$?
;;
stop)
echo -n "Stopping php-fcgi: "
killproc -p $PIDFILE phpfcgi
echo
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
exit $RETVAL
後は、php-fastcgiをサービスに登録しておきます。
# chmod 755 /etc/rc.d/init.d/php-fastcgi
# /sbin/chkconfig --add php-fastcgi
# /sbin/chkconfig php-fastcgi on
# /sbin/service php-fastcgi start
後は、通常通りブラウザからアクセスすれば、サイトを閲覧できます。
ベンチマーク
symfony1.4を使って、"Hello world"を表示するだけの簡単なスクリプトを使います。ツールはApacheBenchを使い、Webサーバ上で実行します。Apache+mod_php (MaxClients 256) とnginx+FastCGI+PHPを比較しました。
①リクエスト数1000回、同時接続数50
Apache: 26[requests/sec](失敗0)
nginx : 27[requests/sec](失敗0)
②リクエスト数1000回、同時接続数100
Apache: 半数以上が失敗
nginx : 27[requests/sec](失敗0)
③リクエスト数1000回、同時接続数200
Apache: 7~8割が失敗
nginx : 21[requests/sec](失敗0)
同時接続数が増えた場合、Aapcheはレスポンスを返せなくなっています。一方で、nginxは同時接続数が増えてもリクエストを処理し、レスポンスを返しました。nginx+FastCGI+PHP構成が常に応答した理由は、リクエストを受け取る部分と、アプリケーションの処理を担う部分が分かれていることにあります。PHPの処理が重くても、サーバへの影響は少なくてすみます。その他、nginxの方がメモリ等のリソースの使用が少ないようです。
nginxにはキャッシュやリバースプロキシの機能もあります。興味があれば、ぜひ試してみて下さい。