アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

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のインストールと設定


FastCGICGIを拡張したものです。通常の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にはキャッシュやリバースプロキシの機能もあります。興味があれば、ぜひ試してみて下さい。