oinume journal

Scratchpad of what I learned

Apacheでリバースプロキシ(mod_proxy)を活用する(3) - 負荷分散編

前回のApacheでリバースプロキシ(mod_proxy)を活用する(2) - 設定編ではフロントエンドのリバースプロキシとバックエンドのCGIサーバの設定を行ないました。今回は、サイトの負荷が大きくなってきた時にバックエンドのサーバを複数台にする設定を説明します。イメージ図としては下記のような感じです。

リバースプロキシでの負荷分散のイメージ

バックエンドの準備

まずは負荷分散が確認できるようにバックエンドのサーバを2台に増やします。前回作成した /etc/apache2/httpd_backend_8080.conf をコピーして /etc/apache2/httpd_backend_8081.conf を作成し、このhttpd_backend_8081.confがListenするポートを以下のように8080から8081にします。


--- httpd_backend_8080.conf 2009-04-07 00:32:55.000000000 +0900
+++ httpd_backend_8081.conf 2009-04-07 00:36:09.000000000 +0900
@@ -1,5 +1,5 @@
#
-# /etc/apache2/httpd_backend_8080.conf
+# /etc/apache2/httpd_backend_8081.conf
#
User www-data
Group www-data
@@ -12,15 +12,15 @@
LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so

ServerRoot "/etc/apache2"
-Listen 8080
-ServerName localhost:8080
-PidFile /tmp/httpd_backend_8080.pid
+Listen 8081
+ServerName localhost:8081
+PidFile /tmp/httpd_backend_8081.pid
ServerAdmin example_at_example.com
DocumentRoot "/var/www/html"
TypesConfig /etc/mime.types
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
-ErrorLog /tmp/error_8080.log
-CustomLog /tmp/access_8080.log combined
+ErrorLog /tmp/error_8081.log
+CustomLog /tmp/access_8081.log combined
UseCanonicalName Off
AddHandler cgi-script .pl

ポートを変更したら、下記のコマンドでこの8081でListenするApacheを立ち上げておきます。

$ sudo /usr/sbin/apache2ctl -f /etc/apache2/httpd_backend_8081.conf -k start

8080のサーバも停止しているようであれば起動しておきましょう。

$ sudo /usr/sbin/apache2ctl -f /etc/apache2/httpd_backend_8080.conf -k start

リバースプロキシで負荷分散の設定

バックエンドのサーバを2台に増設したら、その2台にリクエストを振り分けられるようにフロントエンドのリバースプロキシを設定し直します。やり方は色々ありますが、まずは一番シンプルな「リクエストをランダムに2台に振り分ける」というやり方を試してみたいと思います。

前回の設定では

RewriteEngine on
RewriteRule ^/(.+).pl$ http://localhost:8080/index.pl [L,P,QSA]
RewriteRule ^/(.+).(gif)$ /var/www/html/$1.$2 [L,QSA]

というように、.plファイルへのアクセスを localhost:8080 に振り分ける設定でした。今回はこの部分を変更して、localhost:8080とlocalhost:8081に振り分けるように設定します。具体的には、前回のhttpd.confに対して

RewriteMap server rnd:/usr/local/httpd_proxy_2.2.11/conf/server.txt

という設定をRewriteRuleの前に追加し、RewriteRuleを下記のように変更します。


RewriteRule ^/(.+).pl$ http://localhost:8080/index.pl [P,QSA]
↓
RewriteRule ^/(.+).pl$ http://${server:backend}/index.pl [L,P,QSA]

つまり前回のhttpd.confの設定との差分は下記のようになります。


--- httpd.conf.entry246 2009-04-12 17:22:07.000000000 +0900
+++ httpd.conf 2009-04-12 17:29:49.000000000 +0900
@@ -421,6 +421,7 @@
RewriteEngine on
-RewriteRule ^/(.+).pl$ http://localhost:8080/index.pl [P,QSA]
+RewriteMap server rnd:/usr/local/httpd_proxy_2.2.11/conf/server.txt
+RewriteRule ^/(.+).pl$ http://${server:backend}/index.pl [L,P,QSA]
RewriteRule ^/(.+).(gif)$ /var/www/html/$1.$2 [L,QSA]

httpd.confを書き換えたら、RewriteMapで指定した /usr/local/httpd_proxy_2.2.11/conf/server.txt というファイルを作成します。

# echo 'backend localhost:8080|localhost:8081' > /usr/local/httpd_proxy_2.2.11/conf/server.txt

これらの設定は何を意味するかというと

RewriteRuleで指定したパターンにマッチするリクエストがあった場合、RewriteMapで定義したサーバのどれか1台にランダムでリクエストを転送する

ということです。RewriteMapというディレクティブでは /usr/local/httpd_proxy_2.2.11/conf/server.txt というファイルを指定して、そのファイルの中身は

backend localhost:8080|localhost:8081

となっています。ここで定義したバックエンドのサーバをその後ろのRewirteRuleで ${server:backend} として参照しているわけです。前回の設定では1台にしかリクエストを転送していませんでしたが、このような設定をすることで「どれか1台にランダムで」という形で負荷分散することが可能になります。

というわけで、設定が完了したら mod_proxyサーバを再起動します。

$ sudo /usr/local/httpd_proxy_2.2.11/bin/apachectl -k restart

動作確認

サーバが起動したらブラウザから http://example/index.pl に何回かアクセスしてみましょう(exampleの部分は自身のホスト名に適宜変更してください)。/tmp/access_8080.logと/tmp/access_8081.log の両方に下記のようなログが残っているはずです。

127.0.0.1 - - [12/Apr/2009:17:46:35 +0900] "GET /index.pl HTTP/1.1" 200 129 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ja-JP-mac; rv:1.9.0.8) Gecko/2009032608 Firefox/3.0.8"

これが確認できれば localhost:8080 と localhost:8081 の2台のバックエンドのサーバでの負荷分散環境が構築できたということになります。(なお、例によってそのままの設定だとセキュリティに問題があるので、作業が終了したら起動したApacheのプロセスは止めておくことをお奨めします)

まとめ

mod_proxyを使った負荷分散環境の構築は、バックエンドのサーバさえしっかり準備ができていればリバースプロキシの設定はかなり簡単だったのではないでしょうか。このような複数台のバックエンドのサーバにリクエストを振り分けるような設定は負荷分散としても有効ですが、その他の使い道として「バックエンドのサーバを1台メンテナンスで一時的に止めたい」というような時にサイトを止めることなくメンテナンスが可能になります。(具体的には、server.txtからメンテナンス対象のサーバを削除するだけでリクエストが転送されなくなります)

このように、リバースプロキシの用途は単純な負荷分散以外にもあるので、設定の仕方を知っておくだけでサイトの運用に非常に役立つと思います。