CentOS 7 の Apache 2.4 に mod_heartbeat
とか mod_watchdog
という変なモジュールがあったので興味本位で使ってみました。
使っただけなので詳しいことは調べていません。
概要
Apache の mod_proxy_balancer
で負荷分散するときにリアルサーバからのハートビートを元にバランス先を判断するもののようです。
以下の3つのモジュールを組み合わせて使います。
-
mod_watchdog
- 他のモジュールで定期的なタスクを実行するためのモジュール
-
mod_heartbeat
やmod_heartmonitor
で定期的なタスクを実行するために必要 - リバースプロキシとリアルサーバの両方で有効にする
- いわゆる software watchdog のことではない
- 下記のページが詳しい
- mod_watchdog | しんじつのなみだ
-
mod_heartbeat
- リアルサーバからハートビートを送信するためのモジュール
- リアルサーバで有効にする
- ハートビートはマルチキャストで送信される
- いわゆる Linux-HA の heartbeat とは関係ない
-
mod_heartmonitor
- ハートビートを受信してバランス先を管理するためのモジュール
- リバースプロキシで有効にする
Vagrant
Vagrant で環境を作ります。
Vagrant.configure(2) do |config|
config.vm.box = "ngyuki/centos-7"
config.vm.define "rev" do |cfg|
cfg.vm.hostname = "rev"
cfg.vm.network "forwarded_port", guest: 80, host: 8080
cfg.vm.network "private_network", ip: "192.168.33.10", virtualbox__intnet: "apache-hb"
end
config.vm.define "sv1" do |cfg|
cfg.vm.hostname = "sv1"
cfg.vm.network "forwarded_port", guest: 80, host: 8081
cfg.vm.network "private_network", ip: "192.168.33.11", virtualbox__intnet: "apache-hb"
end
config.vm.define "sv2" do |cfg|
cfg.vm.hostname = "sv2"
cfg.vm.network "forwarded_port", guest: 80, host: 8082
cfg.vm.network "private_network", ip: "192.168.33.12", virtualbox__intnet: "apache-hb"
end
config.vm.provision "shell", inline: <<-SHELL
yum -y install httpd
uname -n > /var/www/html/index.html
SHELL
end
rev がいわゆるリバースプロキシ型の L7 ロードバランサで、sv1 と sv2 がリアルサーバです。
使用している Box はプライベートな Box なのでわたし以外使えませんが、epel-release とか git とかを追加しているだけなので、普通の CentOS 7 と特に変わりありません。
それでは起動します。
vagrant up
mod_heartbeat を使わずに分散
リアルサーバ(sv1/sv2)の Apache を開始します。
systemctl start httpd.service
リバースプロキシ(rev)で次のように設定します。
cat <<'EOS'> /etc/httpd/conf.d/rev.conf
<VirtualHost *:80>
ServerName localhost
<Location />
ProxyPass balancer://app/
ProxyPassReverse balancer://app/
</Location>
<Location /balancer-manager>
ProxyPass !
SetHandler balancer-manager
</Location>
<Proxy balancer://app/>
BalancerMember http://192.168.33.11
BalancerMember http://192.168.33.12
</Proxy>
</VirtualHost>
EOS
Apache を開始します。
systemctl start httpd.service
この状態でリバースプロキシ(rev)にアクセスすると sv1 と sv2 とに分散されているのがわかります。
Vagrant のホスト側から sv2 を強制終了させます。
vagrant halt -f sv2
もう一度 rev を開くと最初の1回目か2回目で超待たされると思います。
これはリバースプロキシが sv2 にリクエストしてタイムアウトを待っているためです。
一度タイムアウトすると、それ以降はしばらく sv1 にのみ振り分けられますが、60 秒ごとに sv2 にリクエストするので、その時にまたタイムアウトを待たされます。sv2 の復帰を確認する必要があるためです。
sv2 を再起動します。
vagrant up sv2
vagrant ssh sv2
sv2 の Apache を開始します。
systemctl start httpd.service
しばらく(最大で 60 秒ぐらい)すると、sv2 にもバランスされるように戻ります。
mod_heartbeat を使ってバランス
すべてのサーバ(rev/sv1/sv2)で、次の通りルーティングを設定します。
ip route add 239.0.0.0/24 dev enp0s8 proto kernel scope link
mod_heartbeat
はマルチキャストでハートビートを送るのですが、送信先の設定で I/F を指定することができないっぽいので、ルーティングでどの I/F から出ていくかを指定する必要があります(普通はこういうときは I/F も指定するもののような気がするけど)。
I/F が一つしかないなら指定する必要はありませんが、Vagrant なので NAT と PrivateNetwork で2つあります。NAT の方から出て行ってもゲスト間で通信できないので、PrivateNetwork から出て行くようにルーティングを設定しています。
リアルサーバ(sv1/sv2)の設定
リアルサーバ(sv1/sv2)で mod_watchdog
と mod_heartbeat
を有効にします。
vim /etc/httpd/conf.modules.d/00-base.conf
次のようにコメントアウトを解除します。
#LoadModule buffer_module modules/mod_buffer.so
-#LoadModule watchdog_module modules/mod_watchdog.so
+LoadModule watchdog_module modules/mod_watchdog.so
-#LoadModule heartbeat_module modules/mod_heartbeat.so
+LoadModule heartbeat_module modules/mod_heartbeat.so
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
#LoadModule usertrack_module modules/mod_usertrack.so
ハートビートのマルチキャストアドレスを指定します(ここで I/F 名を指定できても良さそうな気がするのですが・・・)。
cat <<EOS> /etc/httpd/conf.d/heartbeat.conf
HeartbeatAddress 239.0.0.1:27999
EOS
Apache を再起動します。
systemctl restart httpd.service
tcpdump するとマルチキャストパケットが流れているのが判ります。
tcpdump -nn -i enp0s8 port 27999
リバースプロキシ(rev)の設定
リバースプロキシ(rev)で mod_watchdog
と mod_heartmonitor
を有効にします。
vim /etc/httpd/conf.modules.d/00-base.conf
次のようにコメントアウトを解除します。
#LoadModule buffer_module modules/mod_buffer.so
-#LoadModule watchdog_module modules/mod_watchdog.so
+LoadModule watchdog_module modules/mod_watchdog.so
#LoadModule heartbeat_module modules/mod_heartbeat.so
-#LoadModule heartmonitor_module modules/mod_heartmonitor.so
+LoadModule heartmonitor_module modules/mod_heartmonitor.so
#LoadModule usertrack_module modules/mod_usertrack.so
マルチキャストの受信の設定と、状態を保存するファイル名を設定します。
cat <<EOS> /etc/httpd/conf.d/heartbeat.conf
HeartbeatListen 239.0.0.1:27999
HeartbeatStorage /tmp/hb.dat
EOS
プロキシの設定で lbmethod=heartbeat
を追記します。
cat <<'EOS'> /etc/httpd/conf.d/rev.conf
<VirtualHost *:80>
ServerName localhost
<Location />
ProxyPass balancer://app/ lbmethod=heartbeat
ProxyPassReverse balancer://app/
</Location>
<Location /balancer-manager>
ProxyPass !
SetHandler balancer-manager
</Location>
<Proxy balancer://app/>
BalancerMember http://192.168.33.11
BalancerMember http://192.168.33.12
</Proxy>
</VirtualHost>
EOS
Apache を再起動します。
systemctl restart httpd.service
リバースプロキシ(rev)にアクセスして sv1 と sv2 に分散されていることを確認しておきます。
確認できたら、おもむろに sv2 を停止します。
vagrant halt -f sv2
少し待ってからもう一度リバースプロキシを開くと、先ほどのようにタイムアウトを待たされることはありません。
sv2 からのハートビートが切れたことで、バランス先から取り外されたからです(多分)。
もう一度 sv2 を再起動します。
vagrant up sv2
vagrant ssh sv2
ルーティングを設定して Apache を起動します(本来なら自動で設定されるようにしておくべきです)。
ip route add 239.0.0.0/24 dev enp0s8 proto kernel scope link
systemctl start httpd.service
10 秒ぐらいで sv2 にもバランスされるようになりました。
さいごに
L7 ロードバランサとか、別に Apache でやる必要は全くないと思うし、HAProxy とかでいいと思うし、というか AWS に乗っけて ELB でいいんじゃないって思うので、実際に運用で使うことはないと思います。