負け組アーキテクトの憂鬱

メモしておきたいことや読書の記録を淡々と書く。

FreeBSD

第3の冗長化プロトコル、CARPを試す

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を試してみるかも。

freevrrpdでサーバ冗長化

freevrrpdはFreeBSD、NetBSD、OpenBSDのvrrpd実装。FreeBSDなら/usr/ports/net/freevrrpdにある。

vrrpはルータの多重化を行うためのプロトコルと説明されているけど、特にルータに限定しなくても、普通のホストでも使うことができる。

やっていることは、あるホストが落ちたらそのホストが持っていたIPアドレスを別のホストが引き継ぐ、というイメージ。これを、仮想IPアドレスを定義し複数のホストで共有してやることで実現する。複数のホストのグループはvrrpでグループIDで管理され、この中でプライオリティの最も高いホストがmaster(仮想IPアドレスが割り振られる)、それ以外がbackupとなり、masterが落ちるとbackupの中でプライオリティが高いホストが新しくmasterとなる。freevrrpdでは仮想IPアドレスはmasterとなるホストのIPアドレスエイリアスとして設定される。理屈としてはとてもシンプル。

↓こんなかんじ(192.168.1.253が仮想IPアドレス)

rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::20d:bff:fe4e:8e42%rl0 prefixlen 64 scopeid 0x2
        inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255
        inet 192.168.1.253 netmask 0xffffffff broadcast 192.168.1.253
        ether 00:0d:0b:4e:8e:42
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active

設定はFreeBSDのportsで入れたら/usr/local/etc/freevrrpd.confで。同じディレクトリにfreevrrpd.conf.sampleがあり、丁寧にいろいろなコメントを記載してくれてある。

masterにしたいホストでの設定例

[VRID]
serverid = 1
interface = rl0
priority = 255
addr = 192.168.1.253/32
password = hogehoge
useVMAC = no
sendgratuitousarp = yes

backupにしたいホストでの設定例

[VRID]
serverid = 1
interface = rl0
priority = 250
addr = 192.168.1.253/32
password = hogehoge
useVMAC = no
sendgratuitousarp = yes

設定すべき項目はざっとこんなところ。

  • serveridはvrrpのグループID。紐付けたいホストで同じIDを使う。
  • interfaceはvrrpをしゃべらせたいNICを指定。
  • priorityは優先度。255が最大値で指定されているとmasterになる。
  • addrは仮想IPアドレス。
  • passwordはvrrp通信時のパスワード。グループ内で同じものを指定。
  • useVMACはMACアドレスも仮想のものを使うかどうかの指定。

仮想MACアドレスを使うと、切り替り後も同じMACアドレスで通信できるため、arpの変更が起こらない(ただし、L2SWでは変更に追従する必要がある。まあ、普通は意識しなくてよい)。仮想MACアドレスを使う場合は、切り替り時にホストのMACアドレスが書き換えられるため、もともとIPアドレスが割り振られているばあいにはそれらに影響が出る(可能性がある)。

仮想MACアドレスを使わない場合は、切り替り後に仮想IPアドレスに対応するMACアドレスが(新しいmasterホストのものに)変更される。このため他のホストにMACアドレスの変更を通知してやる必要がある。これを指示するのが、sendgratuitousarp。切り替り後に自分自身のMACアドレスが含まれたarpリクエストをブロードキャストし、結果的にMACアドレスの変更がローカルリンク内に伝播される。

これでfreevrrpdを立ち上げれば最低限のIPアドレスの切り替えは出来るようになる。仮想IPアドレスを使ったサービスの上げ下ろし(DBやhttpdのstart/stopとか)にはmasterscript、backupscriptで指定したスクリプトで行えばいいだろう。

masterscript = /usr/local/bin/master_script.sh
backupscript = /usr/local/bin/backup_script.sh

データの同期や共有ディスクの利用をきちんと考慮してあげれば、なんちゃってHAクラスタ的な使い方が出来る(んじゃないかなあ)。