CARP(Common Adress Redundancy Protocol)とはOpenBSD由来のサーバ冗長化プロトコル。同様なものにCisco SystemsのHSRP、以前試したVRRPがある。なんでまた3つも似たようなプロトコルがあるのかと言えば、乱暴に言ってだいたい以下のような違いがあるようだ。
- HSRP Cisco Systemsのパテント。
- VRRP パテントフリーのHSRPのはずだったが、どうもまだパテント部分が残っているらしい。
- CARP 真のパテントフリーの実装を目指して実装されたもの。
さて、FreeBSDでのCARPの実装だけれども、ユーザランドでの実装とカーネルでの実装があるようだ。ユーザランドでの実装はUCARP。freevrrpdと同じような位置づけだろう(きっと)。これは後日試すとして、今回はOpenBSDのカーネルからポーティングされたと云うカーネルでの実装を試して見たい。結構最近の実装で、対象はFreeBSD 5.4以降のカーネルになる。今回試したバージョンは6月末あたりの6.1-STABLE。
カーネルでの実装、と言うだけあってカーネルの再構築が必要。今のところ標準状態ではLKMも用意されていないようなので、素直に再構築しておこう。以下の行を追加してカーネルを再構築する。
device carp
freevrrpdでは共有アドレスするアドレスは物理ネットワークデバイス(fxp0とかrl0とかde0とか)のエイリアスアドレスとして定義されたが、今回はcarp?という専用のネットワークデバイスが用意される。/etc/rc.confに以下のように記述。192.168.1.253を仮想アドレスとした。
masterにしたいホストでの設定例
cloned_interfaces="carp0" ifconfig_carp0="vhid 1 pass hogehoge 192.168.1.253/24"
backupにしたいホストでの設定例
cloned_interfaces="carp0" ifconfig_carp0="vhid 1 advskew 100 pass hogehoge 192.168.1.253/24"
vhidは仮想ホストを構成する実ホストのグループID。freevrrpで言うところのserveridに等しい。
advskewは死活監視への応答時間。1/256秒を掛けた値だけ遅延し、最初に応答した実ホストが仮想ホストを引き継ぐ。実質的な優先度と考えていいだろう。デフォルトで0なので、backupホストのみ指定すればいいだろう
passは通信時のパスワード。グループ内で同じものを指定すれば良い。
advbaseは今回指定していないが、死活監視の間隔。デフォルトで1秒だが、間隔を長くしたい場合は指定する必要がある(最大255)。
/etc/rc.conf以外に、sysctlもいくつかの設定項目がある。必要ならば/etc/sysctl.confで指定する。
net.inet.carp.allow=1 #carpパケットを受信する。デフォルトは1。 net.inet.carp.preempt=1 #複数のvhidをまとめてフェイルオーバさせたいとき(localとglobalのフェイルオーバを同期させたいなど)指定。デフォルトは0。 net.inet.carp.arpbalance=0 #同一リンクで、arpの応答を使ってバランシングできるらしい。両現用にできるっぽいが未検証。デフォルトは0。 net.inet.carp.log=1 #エラーが起きた時など、ログを記録。デフォルトは1。
ざっとこんなところ。この状態でmaster側でifconfigしてみると、
carp0: flags=49<UP,LOOPBACK,RUNNING> mtu 1500
inet 192.168.1.253 netmask 0xffffff00
carp: MASTER vhid 1 advbase 1 advskew 0
おお、なんかかっこいい。backup側では、
carp0: flags=8<LOOPBACK> mtu 1500
inet 192.168.1.253 netmask 0xffffff00
carp: INIT vhid 1 advbase 1 advskew 100
となっている。実はこの状態ではmasterが通信不能になってもフェイルオーバできない。ifconfigを使ってcarp0をupさせてあげる必要がある。なんか/etc/rc.confで引数にupを指定してもダメっぽい。別のオプションがあるのかもしれないけど探してません。ごめんなさい。
# ifconfig carp0 up
# ifconfig carp0
carp0: flags=49<UP,LOOPBACK,RUNNING> mtu 1500
inet 192.168.1.253 netmask 0xffffff00
carp: BACKUP vhid 1 advbase 1 advskew 100
INITがBACKUPにかわった!!これで設定完了。フェイルオーバさせるには、物理的に抜線してもいいが、さきほど同様にifconfigでcarpインターフェイスをup,downさせてやれば良い。
(master)# ifconfig carp0 down
(master)# ifconfig carp0
carp0: flags=8<LOOPBACK> mtu 1500
inet 192.168.1.253 netmask 0xffffff00
carp: INIT vhid 1 advbase 1 advskew 0
(backup)# ifconfig carp0
carp0: flags=49<UP,LOOPBACK,RUNNING> mtu 1500
inet 192.168.1.253 netmask 0xffffff00
carp: MASTER vhid 1 advbase 1 advskew 100
MASTERの交代が行われているようだ。再度master側でcarp0をupさせると、net.inet.carp.preemptが0のときは即座にMASTERが切り戻され、1の時は切り戻しは起きず、backup側がMASTERのままだった(わかりにくいな・・・)。
しかし、ここで問題が一点。syslogを見ると、
kernel: arp_rtrequest: bad gateway 192.168.1.253 (!AF_LINK)
こんなメッセージが出力されている。ググってみたら「気分悪いけど問題ねーよ」みたいな事が書いてあるが、Gratuitous ARPしようとしてしくじっているように見える。仮想MACに00:00:5e:00:01:01というアドレスを使っているようだが、うちの環境ではどうもこれにスイッチングハブが付いてきていないみたいだ。carp0なんてインタフェイスが出来てるくらいなので、これをrouteに指定してもうまくいかず。実質、物理インタフェイスにalias割り振ったのと同じような動作しかしないようだ。うちでは物理的なスイッチングハブの他に、Virtual Server 2005の仮想スイッチなんかも噛んでるから、切り分けするのがめんどくさくなって今日は終了。次回(いつ?)に続く。
freevrrpdのようにフェイルオーバ時のスクリプトも簡単に指定できるわけではないので(まあ、それがユーザランド実装の強みだしね)、実際に運用するにはいろいろと作り込みが大変そう。ただ、carpのarpバランス機能には興味津々。このへんの期待も込めて、次回はUCARPを試してみるかも。