大規模サイトの作り方 load balancer 編
専用ハードウェアでのロードバランサの性能は当然高いのですが、コストや設置条件等のさまざまな問題で設置できないこともあると思います。
そのような環境下においても、Linux サーバを使って十分な性能のロードバランサを構築することが出来ます。
そんなわけで CentOS 5.7 x86_64 で構築してみました。
CentOS には LVS(Linux Virtual Server) を司る ip_vs カーネルモジュールが既にあり、そのフロントエンドとなるのが ipvsadm コマンドです。
ipvsadm コマンドは以下の要領でインストールします。
# yum install ipvsadm
ロードバランサはいくつか実装方法があります。
単純なのは NAT ですが、戻りパケットもロードバランサを通るのでボトルネックとなりやすいため、今回は DSR(Direct Server Return) という方法で設定したいと思います。
これは MAC アドレスの付け替えにより実現する方法なので、LVS サーバと実サーバは同一セグメントにある必要があります。
ところでこのままだと実サーバに障害が発生した場合に自動的にメンバーから切り離すことが出来ず、またロードバランサ自体に障害が発生すると全滅するといういわゆる単一障害点(SPOF)となってしまうので、なんらかの対策を取らないといけません。
ここでその両方を解決するため keepalived を使います。
keepalived は CentOS 5.x 用の RPM は古いものしかないようなので、以下の要領で作成してインストールしました。
(必要なパッケージはまだあるかもしれません)
# yum install gcc
# yum install openssl-devel
# yum install rpm-build
# yum install kernel-devel
# yum install libnl-devel
# wget http://www.keepalived.org/software/keepalived-1.2.1.tar.gz
# tar xvzf keepalived-1.2.1.tar.gz
# cd keepalived-1.2.1
# ./configure --prefix=/ --with-kernel-dir=/usr/src/kernels/2.6.18-274.12.1.el5-x86_64
# cp ../keepalived-1.2.1.tar.gz /usr/src/redhat/SOURCES/
# make rpm
# rpm -ivh keepalived-1.2.1-5.x86_64.rpm
OS でパケットの転送を有効にします
# vi /etc/sysctl.conf
> net.ipv4.ip_forward = 1
その場で反映させるには以下を実行します。
# sysctl -p
以下で確認できます。
# cat /proc/sys/net/ipv4/ip_forward
keepalived は VRRP の仕組みを使っていますので、iptables でファイアウォールを設定している場合は以下のルールを追加する必要があります。
これがないと VRRP のパケットが届かず、すべてがマスターとして動いてしまいます。
# iptables -A INPUT -p vrrp -j ACCEPT
web サーバ2台の構成での設定例を以下に示します。
global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
}
vrrp_instance VI0 {
state BACKUP
interface eth0
virtual_router_id 100
priority 100
nopreempt
advert_int 1
lvs_sync_daemon_interface eth1
authentication {
auth_type PASS
auth_pass password
}
virtual_ipaddress {
xxx.xxx.xxx.100/28 dev eth0
}
}
virtual_server xxx.xxx.xxx.100 80 {
delay_loop 10
lb_algo lc
lb_kind DR
protocol TCP
sorry_server xxx.xxx.xxx.99 80
real_server xxx.xxx.xxx.101 80 {
weight 1
HTTP_GET {
url {
path /check.txt
status_code 200
}
connect_timeout 3
}
}
real_server xxx.xxx.xxx.102 80 {
weight 1
HTTP_GET {
url {
path /check.txt
status_code 200
}
connect_timeout 3
}
}
}
keepalived のデフォルトの動作はプリエンプティブモードなので、priority の大きい(優先度の高い)サーバが現れるとそちらがマスターに切り替わります。
しかしこの場合、なんらかでマスターが不安定な場合に頻繁に切り替わることになり通信が不安定になる恐れがありますので nopreempt を設定して無効にしています。
バックアップが複数ある場合のマスターの選出は priority で決定されますが、LVSが2台(バックアップが1台)の場合はマスターが落ちれば必然的に残りがマスターに昇格するしかありませんので、priority は同一でも問題ありません。
また、両方 state BACKUP とすることで先に起動した方がマスターになることになります。
config が共通になるので運用上のミスも低減されます。
このあたりについては以下の図書が参考になります。
ログの設定についても軽く触れておきます。
keepalived は syslog の daemon ファシリティでログを出力していますが、/etc/sysconfig/keepalived を以下のように変更することで local1 ファシリティに出力されます。
- KEEPALIVED_OPTIONS="-D"
+ KEEPALIVED_OPTIONS="-D -S 1"
web サーバでの対応
DSR 構成の場合、MAC アドレスの付け替えを行うと説明しました。
NAT と違って宛先 IP アドレスは付け替えられず、このままだと通信できませんので web サーバの方にも少々細工を施します。
Layer3 レベルの話では、eth0:0 に仮想 IP アドレス(xxx.xxx.xxx.100)を付与するだけです。
# ifconfig eth0:0 inet xxx.xxx.xxx.100 netmask 255.255.255.240
/etc/sysconfig/ifcfg-eth0:0 に設定しておくのが良いでしょう。
(alias なので netmask は 255.255.255.255 のような気がしますが、Linux 的にはあまり関係ないようです)
これで着信したパケットが自分のものだと分かるようになりましたが、このままだとスイッチの arp table に仮想 IP アドレスの MAC アドレスとして web サーバが登録されてしまい、うまくロードバランサで振り分けられなくなってしまいます。
このため以下のように arptable を導入し、仮想 IP アドレスの arp 応答をせず、また戻りパケットにも細工してあげる必要があります。
# yum install arptables_jf
# arptables -A IN -d xxx.xxx.xxx.100 -j DROP
# arptables -A OUT -s xxx.xxx.xxx.100 -j mangle --mangle-ip-s xxx.xxx.xxx.101
# /etc/init.d/arptables_jf save
xxx.xxx.xxx.101 は web サーバの IP アドレスです。
これを忘れると通信が出来たり出来なかったりと非常にわかりにくい症状になります。
「Linux高信頼サーバ構築ガイド クラスタリング編」に記述があるのですが、これがまたちょっとだけ間違っておりそのまま適用すると見事にわかりにくい症状となります。
arptables -A OUT -d って書いてあるんですが戻りパケットの送信元なので arptables -A OUT -s が正しいです……。
これで一通りロードバランサが出来ました。
L4 の DSR なロードバランサは非常に負荷も低く良い感じでおすすめです。
ディスカッション
コメント一覧
まだ、コメントがありません