Nginx + lsyncd で WordPress を負荷分散させる

ハイパフォーマンスHTTPサーバ Nginx入門最近、め組ことデジタルキューブさんと、一緒に仕事をやらせてもらってます。
今の所は、主に WordPress サイトの高速化とかやってるんですけど、その中で WordPress サイトを複数台のサーバで負荷分散させて高速化させる案件があったので、その時の作業内容をシェア。
最近はさくらの VPS とか、低価格の VPS が出てきてるので、個人でも手を出せる領域かもしれませんね。
今回は2台のサーバを使って PHP の処理を負荷分散しました。

構成は、こんな感じです。

  • プライマリサーバ ( vps1.example.com : 192.168.0.1 )
     
    • Nginx, Load Balancer、PHP FastCGI のアプリケーションサーバ
    • lsyncd (リアルタイム rsync を実現するためのサービス)
  • セカンダリサーバ ( vps2.example.com : 192.168.0.2 )
     
    • Nginx, PHP FastCGI のアプリケーションサーバ
    • MySQL
    • rsyncd

※ 説明のため IP アドレスはローカルアドレスに設定していますが、実際にはグローバルアドレスを使用しています。
ブラウザからの要求は、すべてプライマリサーバ ( vps1.example.com ) が受け取り、PHP の処理を二台のサーバに分散させます。
もちろん、処理が重くなってきたら、3台目、4台目 と追加していくことが可能です。

実際に行った作業のメモ。

lsyncd の設定

WordPress フォルダのファイルはプライマリサーバで管理し、何か変更があった場合に lsyncd を通じて、セカンダリサーバに配信されます。
配信元のプライマリサーバ側では lsyncd を、配信先のセカンダリサーバ側では rsyncd を、それぞれ作動させます。

配信元プライマリサーバ ( 192.168.0.1 ) の /var/www/html のファイル/ディレクトリを、配信先セカンダリサーバ ( 192.168.0.2 ) の /var/www/html 以下にコピーする設定です。

配信先、セカンダリサーバの設定

rsync, xinetd がインストールされていない場合は yum でインストールしておきます。

$ sudo yum -y install rsync xinetd

rsyncd.conf の設定

$ sudo vi /etc/rsyncd.conf
log file = /var/log/rsyncd.log		← ログファイル
[site]							← 任意の名前
	path = /var/www/html			← コピー先対象ディレクトリ
	hosts allow = 192.168.0.1		← コピーを許可するホスト(配信元プライマリサーバを指定)
	hosts deny = *
	list = true
	uid = root
	gid = root
	read only = false

xinetd, rsync 起動

$ sudo /sbin/service xinetd start
$ sudo /sbin/chkconfig xinetd on
$ sudo /sbin/chkconfig rsync on

iptables でポートを閉じている場合は、配信元プライマリサーバ ( 192.168.0.1 ) から 873 番ポートが接続できるようにしておいてください。

$ sudo vi /etc/sysconfig/iptables
:
-A RH-Firewall-1-INPUT -s 192.168.0.1 -m state --state NEW -m tcp -p tcp --dport 873 -j ACCEPT

$ sudo /sbin/service iptables restart

via. CentOS 5 – rsyncによるファイル/ディレクトリの同期 : Server World

配信元、プライマリサーバの設定

CentOS の場合は yum でインストールしちゃいましょう。rpmforge レポジトリにあります。

$ sudo yum -y install --enablerepo=rpmforge lsyncd

続いて、起動オプションファイルの修正

$ sudo vi /etc/sysconfig/lsyncd
IGNORE_START_ERRORS="--stubborn"

lsyncd.conf の設定

$ sudo cp /usr/share/doc/lsyncd/lrsync.lua /etc/lsyncd.conf
$ sudo vi /etc/lsyncd.conf
----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync.
--
settings = {
	statusFile = "/tmp/lsyncd.stat",
	statusInterval = 1,
	logfile = "/var/log/lsyncd.log",		← ログファイル
}

sync{
	default.rsync,
	source="/var/www/html/",				← 配信元ディレクトリ
	target="192.168.0.2::site",				← 配信先サーバ
	rsyncOps="-az",					← rsync オプション
	excludeFrom="/etc/rsync_exclude.lst",	← 配信除外フォルダのリスト
}

17行目は、配信先セカンダリサーバのIPアドレスと、rsyncd.conf で設定した名前を記入してください。

配信除外フォルダの指定、WP Super Cache プラグインが使用する /wp-content/cache フォルダや、DB Cache Reloaded fix プラグインが使用する /wp-content/tmp/ は、配信除外フォルダとして設定しておきましょう。

$ sudo vi /etc/rsync_exclude.lst
- /wp-content/cache/**
- /wp-content/tmp/**

lsyncd 起動

$ sudo /sbin/service lsyncd start
$ sudo /sbin/chkconfig lsyncd on

これで配信先サーバにファイルがコピーされていれば、おっけです。

via. CentOS 5 – lsyncによるリアルタイムミラーリング : Server World

MySQL サーバの設定

今回 MySQL サーバは、セカンダリサーバ( 192.168.0.2 ) に設置します。
iptables でポートを閉じている場合は、配信元プライマリサーバ ( 192.168.0.1 ) から 3306 番ポートが接続できるようにしておいてください。

$ sudo vi /etc/sysconfig/iptables
:
-A RH-Firewall-1-INPUT -s 192.168.0.1 -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
-A RH-Firewall-1-INPUT -s 192.168.0.2 -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT

$ sudo /sbin/service iptables restart

続いて、ユーザがリモートサーバから接続できるように権限を付与しておきましょう。
WordPress ユーザは wordpress パスワードは password だとすると、こんな感じです。

$ mysql -u root -p mysql
mysql> grant all privileges on *.* to wordpress @"192.168.0.1" identified by 'password ' with grant option ;
mysql> grant all privileges on *.* to wordpress @"vps1.example.com" identified by 'password ' with grant option ;
mysql> grant all privileges on *.* to wordpress @"192.168.0.2" identified by 'password ' with grant option ;
mysql> grant all privileges on *.* to wordpress @"vps2.example.com" identified by 'password ' with grant option ;
mysql> quit;

wp-config.php の DB_HOST の修正も忘れずに行ってください。
セカンダリサーバの IP アドレス、またはサーバ名を指定してください。
localhost のままにしていると、プライマリサーバに処理が振り分けられた場合、MySQL サーバに接続できなくなってしまいます。

mysql サーバをレプリケーションさせると、さらに面白いですね。
余裕のある人は、挑戦してみてください。

Nginx の設定

Nginx で2台のサーバで処理を分散するように設定します。
Nginx の基本的な設定方法は、以下を参照してみてください。
WordPress サイトに nginx を導入する : dogmap.jp

配信先、セカンダリサーバの設定

nginx.conf を修正してプライマリサーバから処理を受け取るように設定しましょう。

$ sudo vi /etc/nginx.conf
:
    server {
        listen      8000;
        server_name vps1.example.com;
        access_log /var/log/nginx/$host.access.log main_x;
        location ~ /\.ht { deny  all; }
        location / {
            root /var/www/html;
            index index.php index.html index.htm;
            if (-f $request_filename) {
                expires 30d;
                break;
            }
            if (!-e $request_filename) {
                rewrite ^(.+)$ /index.php?q=$1 last;
            }
        }
        location ~ \.php$ {
            root /var/www/html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
            #fastcgi_param  HTTPS on;
            include        fastcgi_params;
        }
    }
:

設定を反映させるため Nginx を再起動します。

$ sudo /sbin/service nginx restart

iptables でポートを閉じている場合は、プライマリサーバ ( 192.168.0.1 ) から 8000 番ポートが接続できるようにしておいてください。

$ sudo vi /etc/sysconfig/iptables
:
-A RH-Firewall-1-INPUT -s 192.168.0.1 -m state --state NEW -m tcp -p tcp --dport 8000 -j ACCEPT

$ sudo /sbin/service iptables restart

配信元、プライマリサーバの設定

nginx.conf を修正して2台のサーバに処理を振り分けるように設定しましょう。

$ sudo vi /etc/nginx.conf
:
    upstream backend {
        ip_hash;
        server 127.0.0.1:8000;
        server 192.168.0.2:8000;
    }

    upstream admin {
        ip_hash;
        server 127.0.0.1:8000;
    }

    server {
        listen      8000;
        server_name vps1.example.com;
        access_log /var/log/nginx/$host.access.log main_x;
        location ~ /\.ht { deny  all; }
        location / {
            root /var/www/html;
            index index.php index.html index.htm;
            if (-f $request_filename) {
                expires 30d;
                break;
            }
            if (!-e $request_filename) {
                rewrite ^(.+)$ /index.php?q=$1 last;
            }
        }
        location ~ \.php$ {
            root /var/www/html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
            #fastcgi_param  HTTPS on;
            include        fastcgi_params;
        }
    }

    server {
        listen       80;
        server_name   vps1.example.com;
        access_log /var/log/nginx/$host.access.log main;

        location /wp-admin { proxy_pass http://admin; }
        location /wp-includes { proxy_pass http://admin; }
        location /wp-login.php { proxy_pass http://admin; }
        location /feed { proxy_pass http://backend; }
        location ~ .*\.php { proxy_pass http://backend; }
        location ~ .*\.sql { deny  all; }
        location ~ /\.ht { deny  all; }
        location ~ .*\.(txt|xml|html?|js|css|gz|ico|jpe?g|gif|png|wmv|flv|swf|mpg) {
            root    /var/www/html;
            index   index.html index.htm;
            if (-f $request_filename) {
                access_log  off;
                ssi     on;
                expires 30d;
                break;
            }
        }
        location / {
            root    /var/www/html;
            index   index.php index.html index.htm;
            if ($http_cookie ~* "comment_author_[^=]*=([^%]+)%7C|wordpress_logged_in_[^=]*=([^%]+)%7C") {
                proxy_pass http://admin;
                break;
            }
            proxy_pass http://backend;
        }
:

5,6 行目で、2台のサーバをバックエンドとして使用するように設定しています。
ちゃんと処理がラウンドロビンされているかを確認するには Nginx のログを確認してみてください。

45〜47, 65〜68行目ではログインした場合は、必ずプライマリサーバに接続するように設定しています。
こうしておかないと、メディアアップロードした時とかセカンダリサーバにファイルがアップロードされてしまう可能性があるので、注意が必要です。

後は Nginx を再起動すれば、ロードバランスされるようになります。

$ sudo /sbin/service nginx restart

今回の設定ファイルの中には Proxy Cache の設定は含んでいませんが、実際のサイトでは Proxy Cache も有効にしています。

Nginx + lsyncd で WordPress を負荷分散させる」への2件のフィードバック

  1. ピンバック: #Wordpress でHyperDBを使ったときの運用の疑問 | 5丁目通信(仮称)

  2. ピンバック: 活動ログ 2011/07/19 « Lifelog « Laddy in

コメントを残す

メールアドレスが公開されることはありません。