負荷分散構成で、通常はWEBサーバをLBでラウンドロビンさせているけど、特定の操作のあいだはずっと同じサーバに振り分けたいというニーズは、ままあるかと思います。
例えば課金処理のセッションの開始から終了までとか、XSS対策でワンタイムトークンの突き合わせをおこなうとか。
同じIPであれば、L4のLBでもIPのセッション維持で片側に倒すことはできますが、スマホの移動中やテザリングなど、途中でIPが変わる場合は対応できません。
かといってL7のLBでクエリから接続するサーバを振り分けるにも、L7は高いので、予算的に難しいことも多いと思います。
ここでは、Apacheのmod_proxyを使って、サブドメインによって接続するサーバを切り替える、という方法を書きとめておきます。
アプリケーション層から制御できるため、柔軟で、しかも費用がかかりません。
環境:
CentOS 6.5
Apache 2.2.7
構成:
WEBサーバ1 web1 (192.168.1.11)
WEBサーバ2 web2 (192.168.1.12)
ルール:
ドメイン test.com(サブドメインなし) 宛 => web1かweb2のいずれか
ドメイン www1.test.com宛 => web1
ドメイン www2.test.com宛 => web2
イメージ:
設定:
@web1
vi /etc/hosts 192.168.1.12 web2 www2.test.com
vi /etc/httpd/conf/httpd.conf <VirtualHost 192.168.1.11:80> (略) <IfModule mod_rewrite.c> #プライベートネットワーク以外からのアクセスでwww2.test.com宛の接続はweb2へ RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.\d+$ RewriteCond %{HTTP_HOST} ^www2\.test\.com$ RewriteRule ^(.+) %{HTTP_HOST}$1 [C] RewriteRule ^www2\.test\.com(.*) http://www2.test.com$1$2 [P,L] </IfModule> </VirtualHost>
@web2
vi /etc/hosts 192.168.1.11 web1 www1.test.com
vi /etc/httpd/conf/httpd.conf <VirtualHost 192.168.1.12:80> (略) <IfModule mod_rewrite.c> #プライベートネットワーク以外からのアクセスでwww1.test.com宛の接続はweb1へ RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.\d+$ RewriteCond %{HTTP_HOST} ^www1\.test\.com$ RewriteRule ^(.+) %{HTTP_HOST}$1 [C] RewriteRule ^www1\.test\.com(.*) http://www1.test.com$1$2 [P,L] </IfModule> </VirtualHost>
これで、www1.test.comへのアクセスは常にweb1へ、www2.test.comへのアクセスは常にweb2へ、サブドメイン指定なしのtest.comはラウンドロビン、になります。
デメリットとしては、LBではなくWEBサーバが振り分けるため、リダイレクトによるネットワークコストがかかります。
また、未検証ですが、LB側で重み付けやIPでセッション維持をおこなっていると、LBはweb1へ振り続け、WEBサーバはweb2に振り続け、といったリダイレクトのループが発生してしまうかもしれません。