Ultra Monkey とは、Linux-HA (High Availability=高可用性) プロジェクト、LVS (Linux Virtual Server) プロジェクトの産物を中核とした様々なツールを組み合わせて、冗長化と負荷分散、つまり広義のクラスタを Linux で実現しようというプロジェクト。ここでは、RedHat Enterprise Linux 4 (RHEL4) と Fedora Core 5 での検証に基づいて実装方法を解説する。
Ultra Monkeyには、TCP/IP(7層のOSI参照モデル) のL4でロードバランスをする元祖 Ultra Monkey と、それを拡張した UltraMonkey-L7 とがある。当ページで検証したのは L4 のほうだ。L7版の検証は別ページにまとめた。
UltraMonkey をよりよく理解したいのなら、UltraMonkey.org サイトの上部にある English >> Ultra Monkey 3 とリンクを辿り、Configuration の項を読むことをお勧めする。
Ultra Monkey は、主として 3つのコンポーネントで成り立っている。この他に、もちろん LVS (Linux Virtual Server) フレームワークがカーネルに含まれていることが必要だが、最近の Linux ディストリビューションではコンパイル済みであることがほとんどで、 RHEL4 および Fedora Core 5 でも LVS は出来合いのカーネルに既に含まれている。
ipvsadm | : LVS に実サーバを登録したり削除したりロードバランス比を変えたりという実際の命令を行うコマンド。 ipfwadm や ipchains, iptables に似たコマンド形式を持つ。 |
ldirectord | : ロードバランサーデーモン。定期的に実サーバ (例えば httpd サービス) の死活確認を行い、ipvsadm 経由で LVS を操作する。中核となる ldirectord 実行ファイルは Perl で書かれている。ここで言う死活確認は主にアプリケーション層でのテストを指す。 |
heartbeat | : 高可用性デーモン。ロードバランササーバどうしで死活確認を行い、仮想IPアドレスを有効化/無効化したり、必要なほうでのみ所定のサービス (当解説においては ldirectord) を起動させたりする。ここで言う死活確認は低レベル (TCP/IP のインターネット層やネットワークリンク層) でのテストが主。 |
左図は、4台のマシンで高可用性と負荷分散を実装する基本的なトポロジー。
ここでは、インターフェイス eth0:0 は LVS および heartbeat によって生成される仮想IPアドレスで、今アクティブな ldirectorサーバ ldirector1 では有効、スタンバイ状態の ldirector2 では無効になっている。 heartbeat は HUB (L2スイッチ) への定期的な ping によって自サーバおよびネットワーク経路や実ネットワークインターフェイスの健常性を確認しており、なお且つ、ふたつの heartbeat どうしは LAN のマルチキャストやユニキャストあるいはシリアルケーブル経由で互いの死活を確認するとともに、状態を通知し合う。もしもこの時点で ldirector1 サーバが異常を来すと、LAN かシリアルのうちその時まだ利用可能な経路を使って相手に「ワシ死んだから」と伝え、ldirector1 上では heartbeat が仮想IPアドレスを無効化するとともに ldirectord を停止し、代わって ldirector2 上で仮想IP が活性化し ldirectord が起動されることになる。
起動しているほうの ldirectord は、(この例では) 実Webサーバ webserver1 と webserver2 に対して定期的に死活確認用コンテンツ(htmlページ) を HTTP プロトコルで要求することによって、サービスが正常に提供可能かどうか確認している。もしも webserver2 の httpd が正常な返答を返さなくなると、ldirectord は LVS の実サーバリストから webserver2 を削除する (復活したら自動的に再登録される)。
クライアントから実際の HTTP リクエストが来ると、ldirectord の発生させる仮想Webサービス (TCPポート80で待ち受け) が一旦それを受け、ふたつの実サーバへラウンドロビン方式 (そう設定してあれば) でパケットをリダイレクトする。この図では、ldirectord から実サービスへの転送はダイレクトルーティング方式 (gate) に設定してあるので、HTTP 応答は実サーバが ldirectorサーバを介さずに直接ネットワークへ返す。上図の lo:0 エイリアスインターフェイスはそのためのもので、webserver1/2 とも、lo:0 に持たせる IPアドレスは ldirectorサーバの持つ仮想IPと同一のものだ。
トポロジーはいろいろな構成が可能で、この図は一例にすぎない。例えば、ldirectorサーバそれぞれにふたつのネットワークカードを装備し、ldirectord からの転送方法をダイレクトルーティング方式でなく NAT方式 (masq) にすると、ldirectorサーバは一種の L4スイッチ (ルータ) になる。その場合、 ldirectord はパケットの送信元アドレスをパケットの入ってきたインターフェイスの IP にすげ替えてから実サーバに渡すので、HTTPレスポンスもまた必ず ldirectorサーバを通って返って行くことになる(※)。なお、その場合には実サーバに lo:0 エイリアスインターフェイスを作らなくていい代わりに、 ldirectorサーバで別途 iptables を使い IPマスカレードを施してやる必要がある。実サーバの提供するサービスは HTTP とは限らず、当ページ執筆時点の ldirectord では ftp, smtp, pop, ldap, https, dns, mysql, pgsql などがサポートされている。また、はなから ldirectord は使用せずに、 heartbeat だけを使って、例えば 2台の Apache サーバで冗長構成だけを組むこともできる。またその反対に、ldirectord だけを装備してロードバランスだけを行うことも可能だ (この場合、もちろん ldirectord サーバが単一障害点となりうる)。
※ NAT方式で実装する場合には、実サーバのデフォルトゲートウェイに ldirectorサーバの内側インターフェイスの IPアドレスを指定しておく。
LinuxでHAクラスタ・ロードバランサを構築するには他のソフトウェアの組み合わせもある。主なものを一覧にしてみた。
パッケージスィート | 高可用性(HA) | ロードバランス | ||
クラスタ制御 | リソース制御 | フレームワーク | 実サーバ死活監視 | |
Ultra Monkey | heartbeat | LVS(ipvsadm) | ldirectord | |
LVS + Piranha | pulse | LVS(ipvsadm) | nanny | |
RHEL6標準のL4バランサ。基本的な設定はphpベースのWeb GUIでできる。Piranha(ピラニア)プロジェクトは終了しており、RHEL7(?)では廃止される見込み | ||||
LVS + Keepalived | keepalived | LVS(ipvsadm) | keepalived | |
L4レベルでのロードバランス及び振り分け先固定が可能。仮想IPはVRRPで発生させる。keepalivedは、プレビュー扱いながらRHEL6に標準パッケージ有 | ||||
Ultra Monkey L7 | heartbeat | l7vsd(l7vsadm) | l7directord | |
L7でのロードバランス及び振り分け先固定が可能。L4での振り分けも可能だがそれなら元祖L4版を使ったほうがいいだろう | ||||
または | corosync | pacemaker | l7vsd(l7vsadm) | l7directord |
RHEL6ではpacemakerとcorosyncの標準RPMがあるため、この組み合わせのほうがインストールしやすい。別ページで検証している | ||||
LVS + HAProxy | heartbeat | pacemaker | LVS(ipvsadm) | haproxy |
L7及びL4でのロードバランス及び振り分け先固定が可能。ただしSSLが扱えるようになったのは最近。haproxyはプレビュー扱いながらRHEL6に標準パッケージ有。heartbeatの代わりにpacemaker+corosyncを使う手もある |
上記の基本構成ではマシンが 4台も必要で、あまりにももったいない。そこで、当解説では、ldirectorサーバを実Webマシンに取り込んだ形態を採ることにする (Ultra Monkeyオフィシャルサイトの解説で言うところの Streamline構成)。つまり、基本トポロジーで ldirectord が webserver1 と webserver2 へパケットをリダイレクトしていたところを、ローカルか他者かの振り分けにするわけだ。
構築手順全体の流れとしては、Ultra Monkey の各コンポーネントの仕組みが分かりやすいように、まずは webserver1 でのみ ldirectord を動かして負荷分散のみ実装し、その後 webserver2 でも ldirectord を設定して heartbeat による高可用性を実装していこうと思う。ただし、 Ultra Monkey のコンポーネントは、邪魔になるわけではないので両サーバとも全てインストールする。
必要なパッケージを依存関係上必要なものも含めて RHEL4 と Fedora Core 5 に分けてリストアップしたのが下の表だ。Perl モジュールに関しては、Fedora Core 5 では必須かどうかが不確かなのだが、Yum を使えば入れるのは容易いし害にもなりそうにないので、筆者はインストールすることにしている (RHEL4では必須)。基本的には表の上のグループから下へとインストールしていく。
Fedora Core 5 では全てディスリビューションオフィシャルパッケージで間に合うが、RedHat Enterprise Linux 4 の場合は、Ultra Mokney L7(SourceForge) のサイトへ行き、UltraMonkey(L4) の中で自分のアーキテクチャに合ったものをダウンロードする。その中に全てのバイナリパッケージやソースRPM、SPECファイルなど一式がそろっている;
○=必要, ×=不要, △=通常不要あるいは不確かなもの
Std=OS標準RPM, Ext=FedoraのYumでExtrasレポジトリのもの, UM=UltraMonkey付属RPM, BB=パッケージビルドしてからインストール(後述)
分類 | パッケージ(カッコ内はRHELの場合の名称) | RHEL4 | Fedora 5 | 備考 |
lib | glib-devel | ○ Std | × | |
PM | perl-Digest-HMAC | ○ Std | ○ Std | |
perl-Digest-SHA1 | ○ Std | ○ Std | ||
perl-Crypt-SSLeay | ○ Std | △ Std | ||
perl-Convert-ASN1 | ○ Std | △ Std | ||
perl-GSSAPI | △ ? | △ Ext | Fedoraでは△のものを入れるには依存関係上必要。RHEL4では気にしていなかったので不明 | |
perl-HTML-Parser | ○ Std | ○ Std | ||
perl-HTML-Tagset | ○ Std | ○ Std | ||
perl-IO-Socket-SSL | ○ UM | △ Ext | ||
perl-LDAP (perl-ldap) |
○ Std | △ Std | ||
perl-libwww-perl | ○ Std | ○ Std | ||
perl-Net-DNS | ○ Std | ○ Std | ||
perl-Net-IP | ○ UM | ○ Std | ||
perl-Net-SSLeay (perl-Net_SSLeay.pm) |
○ UM | △ Ext | ||
perl-URI | ○ Std | ○ Std | ||
perl-XML-NamespaceSupport | ○ Std | △ Std | ||
perl-XML-SAX | ○ Std | △ Std | ||
perl-XML-Parser | ○ Std | ○ Std | ||
perl-Authen-SASL | ○ UM | △ Ext | ||
perl-MailTools | △ Std? | △ Ext | ldirector.cfでemailalertを設定したい時のみ必要 | |
perl-Mail-IMAPClient | ○ UM | △ Ext | ||
perl-Parse-RecDescent | ○ UM | △ Std | ||
LVS | ipvsadm | ○ BB | ○ Std | RHELの場合はUltraMonkeyアーカイブのSRPMS/下のipvsadmソースパッケージからRPMをビルドする。付属のSPECファイルではうまくいかないので、その際には小生のカスタムSPECファイルを使用(後述) |
HA | libnet-devel (libnet) |
○ UM | ○ Ext | RHELではUltraMonkeyアーカイブのADDONS/libnetをインストールする |
heartbeat | ○ BB | ○ Ext | RHELの場合はUltraMonkeyアーカイブのSRPMS/下のheartbeatソースパッケージからRPMをビルドする。UltraMonkeyアーカイブに含まれるものは 1.2.3、Fedora では 2.0.x とメジャーバージョンが異なる | |
ldirectord (heartbeat-ldirectord) |
○ BB | ○ Ext | 上記と一緒にビルドされる | |
pils (heartbeat-pils) |
○ BB | ○ Ext | 上記と一緒にビルドされる | |
stonith (heartbeat-stonith) |
○ BB | ○ Ext | 上記と一緒にビルドされる | |
Arp | arptables_jf | △ Std | × | iptablesのARP版といったところ。RHEL3 などの古いカーネルでは必要だったようだが、カーネル 2.6.9 以降では proc で設定できるので不要となった |
arptables-noarp-addr | × | × | ||
Misc | fedora-usermgmt | × | ○ Ext | heartbeatパッケージが依存 |
fedora-usermgmt-setup | × | ○ Ext | heartbeatパッケージが依存 | |
fedora-usermgmt-shadow-utils | × | ○ Ext | heartbeatパッケージが依存 |
カーネルバージョンに依存する部分があるので、ソースRPMからビルドしてからインストールする。RHEL4 の 64ビット版 smpカーネル上でコンパイルしようとしたところ、うまくいかなかったので、Ultra Monkeyアーカイブに含まれる SPECファイルをベースにして修正したものを作った。
ダウンロードしたら、下記の斜体の部分を自分のカーネルに合わせてから rpmbuild していただきたい。kversion の値は現在使用しているカーネルの正確なバージョン、kdevel はそれに呼応する (インストールされている) カーネル開発RPMパッケージからバージョン部を取り除いたもの。
%define kversion 2.6.9-55.0.2.EL-smp-x86_64 %define kdevel kernel-smp-devel
コンパイルできたら *-degubinfo-* 以外のパッケージをインストールする。
これにもカーネルバージョンに依存する部分があるはずなので、ソースRPMからビルドしてから入れる。ビルドするには先に libnet パッケージをインストールしておかなければならない。ビルドできたら *-debuginfo-* 以外をインストールする。
インストールの項で述べたように、仕組みが理解しやすいよう順を追って構築していくことにする。
まずは heartbeat 抜きで、片方の実サーバでだけ ldirectord を動作させ、HTTP (TCPポート80) の負荷分散のみを実装する。
・ldirectord はダイレクトルーティング (gate) 方式 |
・実サービスへの振り分けはウェイテッドラウンドロビン |
・死活確認用コンテンツは静的HTMLファイル |
webserver2 は通常のスタンドアロンWebサーバとほとんど変わらないわけだが、ldirectord をダイレクトルーティングで使用するため、webserver2 でも、仮想IPと同じアドレスを持つネットワークインターフェイスをループバックのエイリアスとして作成する。それに伴い、ARPへの返事を限定するための ARP応答仕様の修正も行う必要がある。
仮想IPと同じIPアドレスを持つエイリアスインターフェイスを作るというマニュアル通りのやり方と、(検証中ながら) iptables で DNAT する方法とがある。まずは教科書通りの段取りを説明する。iptabels による方法は後述のコラムを参照。
エイリアスインターフェイスの必要な理由はこうだ。
ldirectord を NAT (masq) でなくダイレクトルーティング (gate) で使う場合には、ldirectord による仮想サービスが一時受取りした HTTP トラフィックは、送信元アドレスもそのまま、宛先アドレスも LVS の仮想IP(当例では 192.168.1.250) のままで、宛先MACアドレスだけを実HTTPサーバのものに変えて再送信される。これを、別の呼び方では MAT (MAC Address Translation) と言う。ここでもし、実サーバが 192.168.1.250 を自分の IP として認識していなければ、実HTTPサーバは ldirectord から転送されたパケットを受け取らずに破棄してしまう。
エイリアスインターフェイスの作成は GUI (system-config-network) で行う手もあるが、狙った内容だけを的確に設定するには、やはり /etc/sysconfig/network-scripts/ifcfg-lo:0 ファイルをエディタで直接作成するのが一番。内容は以下の通り。ネットマスクが 255.255.255.255 なのは、まさにそのアドレスにだけ返答するようにしなければならないからだ;
DEVICE=lo:0 TYPE=Ethernet BOOTPROTO=static BROADCAST=192.168.1.255 IPADDR=192.168.1.250 NETMASK=255.255.255.255 NETWORK=192.168.1.0 ONBOOT=yes NAME=loopback
書いて保存したら、早速反映させる;
root# ifup lo\:0
上記に伴い、ARP リクエストへの回答を制限する。ネットワークデバイス (ルータやハブや他のコンピュータ) から「全員に告ぐ。IPアドレス 192.168.1.250 を持ってる者がいたら MACアドレスを答えるように」と言われた時に、ARP を受け取ったネットワークインターフェイス自体がそのものずばりの IPアドレス (IPエイリアスやセカンダリアドレスも含む) を持っている時にだけ返事をするようにしなければならない。ループバックにその IPアドレスを持っているからといって「それオレだよオレ」とホイホイ答えられては、立候補者が 2人も 3人も出てしまってルーティングが成り立たないのだ。そのためには、/proc/sys/net 下の然るべきパラメータに然るべき値を設定しなければならない。設定は、マシンのブート時に必ず設定されるよう /etc/sysctl.conf に以下の要領で書く。
net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.eth0.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2 net.ipv4.conf.eth0.arp_announce = 2
eth0 以外にも eth* デバイスがある場合はそれらについても同様に記載すること。変数の意味を知りたければ、 kernel-doc パッケージをインストールして /usr/share/doc/kernel-doc-x.x.x/Documentation/networking/ip-sysctl.txt を読むべし。
HTTP 宛てのパケットが ldirectord によって内部的にフォワードされることになるので、ldirectord を動作させる方のサーバでのみ、上記に加えて ip_forward も有効にする。
net.ipv4.ip_forward = 1
必要な sysctl 値を全て /etc/sysctl.conf に書いたら、反映させる;
root# sysctl -p
理論的には、ループバックにエイリアスインターフェイスを作る代わりに、iptables でDNAT(Destination NAT) を掛けてやることによっても、MATされたパケットを実サーバで受け取ることができるはず。これが上手くいくなら、ARP応答の振る舞いを変えるなどということもしなくて済む。ただし、この手は、実サーバに ldirectord を同居させた Streamline構成では難しいと思われる。実サーバで、ip_forward を有効にした上で、nat テーブルに次のような宛先NATルールを設定する。
iptables -t nat -A PREROUTING -i eth0 -d 192.168.1.250 -p tcp --dport 80 -j REDIRECT --to-ports 80
噛み砕くと「eth0から入ってきて、宛先IPが仮想IPで、宛先ポート80のTCPパケットだったら、自分自身のポート80へリダイレクトする」というルールだ(宛先ポートは無変更なので最後の '--to-ports 80' は省略可能)。REDIRECTアクションは「自分自身の」というところが理解しづらい。同じことを、より具体的で説明的な DNATルールに書き換えると下記のようになる(こちらも最後の ':80' は省略可能)。
iptables -t nat -A PREROUTING -i eth0 -d 192.168.1.250 -p tcp --dport 80 \ -j DNAT --to-destination 192.168.1.1:80
つまり、パケットの入ってきたインターフェイス(つまり当例ではeth0) のIPアドレスへ宛先NAT しているわけだ。REDIRECTアクションには、パケットが入ってくる度に eth0 のIPを割り出すという内部処理が伴う。そのため、非常にトラフィックの多いWebサーバの場合、もし実サーバ1台1台ルールを変える面倒を惜しまないのなら、CPUへの負荷や処理スピードの面で優れる後者の方がお勧めできる。どちらのルールでも、実Webサーバからの戻りパケットは自動的に逆DNATされる。
実用に際しては、IPフォワードを他者に悪用されないためのルールも敷いたほうがいいだろう。というわけで、今話題にしている事柄だけを網羅した最低限の /etc/sysconfig/iptables は下記のようなものになる。
*nat :PREROUTING ACCEPT :POSTROUTING ACCEPT :OUTPUT ACCEPT -A PREROUTING -i eth0 -d 192.168.1.250 -p tcp --dport 80 -j REDIRECT COMMIT *filter :INPUT ACCEPT :FORWARD DROP :OUTPUT ACCEPT -A FORWARD -m state --state ESTABLISHED -j ACCEPT -A FORWARD -i eth0 -d 192.168.1.250 -p tcp --dport 80 -m state --state NEW -j ACCEPT COMMIT
テーブルとは何ぞやとかルールの書き方などはここではとても扱いきれないので、詳しくは iptablesのページ や Iptablesチュートリアル をお読みいただきたい。特に、Iptablesチュートリアルの 「テーブルとチェーンの道のり」の章はしっかりと押さえておくべきだろう。
ldirectord の設定ファイルは /etc/ha.d/ldirectord.cf。
ディレクティブ | 説明 |
基本フォーマット | [グローバルセクション] virtual=... の外に書いた設定は、全ての virtual セクションのデフォルト値となる。 [virtualセクション] virtual= で始まる行とそれに続くインデントされた行が、ひとつの仮想サービス定義となる。仮想サービスは、"IPアドレス"、"IP(またはリゾルブ可能なホスト名):ポート"、/etc/services で解決可能な "サービス名"、fwmark の値、のいずれかを使って定義できる。virtual 内で設定したディレクティブはグローバルセクションでのものをオーバーライドする。 #で始まる行はコメントとして無視される。 |
checktimeout= | 実サーバへの接続テストに返答がない時、異常として判定を下すまでの回答待ち時間 (秒)。デフォルトは 5秒。 |
checkinterval= | 実サーバへの接続テストを行う間隔 (秒)。デフォルトは 10秒。 |
autoreload= | ldirectord.cf が変更されたら自動的にリロードする。変更の有無はファイルのタイムスタンプによって判定される。デフォルトは no。 |
logfile= | ldirectord のログの書き出し先を絶対パスで指定する。値が `/' で始まっていない時は syslog のファシリティとみなされメッセージは syslog に送られる。 |
quiescent= | no では、異常と認められた実サーバは LVS リストから削除される。 yes の時は、振り分けウェイトを 0 にするだけで削除はしない。後者の場合、実サービスが持続的 (persistent) な接続を使用している時には、それまでに既にセッションを開始していたクライアントからのリクエストは、持続的接続の期限が切れるまでは死んだほうの実サーバへ引き続き転送されてしまうので注意が必要。 |
real= | 仮想サービスのロードバランス先とする実サービスを定義する。例では real= をふたつ連ねてふたつのサーバ (サービス) を定義しているが、IP は範囲でも指定でき、ポートはサービス名でも指定できるので、 real=192.168.1.1->192.168.1.2:http gate と書くやり方もある。 |
gate [weight] | real=... に続く gate は、実サーバへのパケット転送にダイレクトルーティングを使用することを意味する。他に masq と ipip があり、masq はマスカレード (動的送信元アドレス変換)、ipip では IPトネリング (カプセル化) による転送を行う。 また、gate の後ろに振り分けウェイトを指定することもできる。例を挙げると、 real=192.168.1.1:80 gate 3 real=192.168.1.2:80 gate 2 と設定しておけば実サーバ .1.1 と .1.2 に 3:2 の比重でトラフィックを振り分けることができる。後述の scheduler ディレクティブも参照のこと。 |
fallback= | 健常な実サーバがひとつもない時の最終振り分け先とするサーバとポート。 |
checktype= | 実サービス死活チェックの方法。幾つかの値や書き方がある (デフォルトは negotiate)。 negotiate : request=で指定したコンテンツをアプリケーション層で要求し、回答を receive= の文字列と比較する。ただし SQL の場合は回答の比較は行われない。 connect : TCP/IP トランスポート層での単純な接続テスト。 ping : ICMPエコーつまり ping によるテスト。 数値 : 例えば 5 とだけ書いておくと、5回に 1回だけ negotiate 方式のテストを行い、それ以外は connect テストを行う。 off : チェックは行わず、どの実サーバもフォールバックサーバも活性化は行わない。 on : チェックは行わず、どの実サーバもフォールバックサーバも非活性化は行わない。 |
service= | checktype= が negotiate または数値の時に、negotiate テストに使用するアプリケーションプロトコル。現在のところ ftp, smtp, pop, http, https, ldap, dns, mysql, pgsql などがサポートされている。 |
request= | checktype= が negotiate または数値の時に、そのアプリケーションプロトコルで要求するオブジェクト。http(s) では例の通り。dns の場合は Aレコードか PTRアドレス、mysql, pgsql では SQLクエリ文を書いておく。 |
receive= | checktype= が negotiate または数値の時に、実サーバからの回答に期待する文字列の正規表現。つまり、例のように "up and running" とした時には、"It's not up and running." というレスポンスが返ってきても真となることに注意。チェックプロトコルが mysql または pgsql の場合は回答内容の比較は行われないのでこのディレクティブは無意味。 |
scheduler= | 振り分けに使用するアルゴリズム。 rr : 均等なラウンドロビン。 wrr : ウェイト比設定を加味したラウンドロビン。 lc : その時コネクションの最も少ないサーバへ優先的に振り分ける。 wlc : lc にウェイト比設定を加味したもの (デフォルト)。 他に lblc(Locality-Based Least-Connection), lblcr(Locality-Based Least-Connection with Rplication), dh(Destination Hashing), sh(Source Hashing), sed(Shortest Expected Delay), nq(Never Queue) があると ldirectord の man には書かれている。詳しくは LVS サイトの "Job Scheduling Algorithms in Linux Virtual Server" を参照。 |
persistent= | 値は 1 以上の秒数。ひとつのクライアントからのリクエストは、最初のリクエストからこの秒数間は (その実サーバが死なない限り) 同じ実サーバへ振り分けられる。デフォルトでは無効 (※)。SSLを伴ったアプリケーションプロトコルでは長めにしたほうがいいらしい。また、keepalive を On にした httpd でも、長めにするのがよさそう。FTP では、ldirectord をダイレクトルーティングや IPトネリングで転送する時には長めがよいが、マスカレードの場合には persistent を無効のままにして 「ip_vs_ftp カーネルモジュールをロードせよ」と ipvsadm の man に書かれている。 |
protocol= | トランスポート層プロトコル種別。仮想サーバを "IP(またはホスト名):ポート" で指定した場合は tcp または udp のどちらかで、省略時には tcp となる。仮想サーバを fwmark で指定した場合、ここで指定できるのは fwm のみ。 |
emailalert= | 実サーバが LVS から削除/登録されるなど LVS の状態が変わった時に通知メールを送る宛先メールアドレス。ただし、Fedora Core 5 で実験したところ、1) "hoge@hoge.com" のような完全メールアドレスを書くと To: がおかしな形式になる 2) 送信者が root@hostname 固定で変える術が用意されていないなど、機能は不十分。よって、使うとしても emailalert="root" のようにドメイン抜きで指定してローカルマシン上の UNIXユーザへ送る程度にとどめておいたほうがよさそう。 |
emailalertfreq= | 上記 emailalert を設定した時、実サーバが LVS から削除され引き続き復活しない場合に警告メールを再び送信するまでの間隔 (秒)。 0 に設定すると、削除された時点で 1度だけ送り、その後は二度と送らない。 |
※ ldirectord.cf で persistent の無効を指示するには persistent=... ディレクティブをはなから書かなければよい。persistent=0 とやってみたところ LVS が正常に機能しなかった。これは、設定の結果として ldirectord が `ipvsadm -E -t 192.168.1.250:80 -s wrr -p 0' というコマンドを発生させてしまうからだ。 ipvsadm コマンドの -p オプションの引数は、1 以上を指定するか省略するかのどちらかでなければならない。 ipvsadm 自体では引数なしの -p を指定した時にはデフォルトの 300秒が採られることになっているが、ldirectord が引数なしの -p を ipvsadm に渡すことはない。
ldirectord.cf に合わせて、監視される実サービスの死活確認コンテンツを用意し、サービスデーモンに必要な調整を加える。ここでは実サービスが Apache である場合を前提に解説する。
まず、前出の ldirectord.cf では、死活確認用コンテンツを request="hachecker/hacheck.html", 正常時に期待する正規表現文字列を receive="up and running" と設定した。それに合わせれば、下記のような内容の hacheck.html を Apache ドキュメントルート/hachecker/ に作成する (あるいは Apache の Alias機能でマッピングするなどお好みで) ことになる。 hacheck.html の内容はこれだけ;
up and running
前にも書いたことだが receive= の値は正規表現なので、`up and running' を `<html><body> </body></html>' 等の HTMLタグで囲んでも ldirectord はこれを正常とみなす。が、そんなタグは無駄にトラフィックを増やすだけであり、お勧めはしない。なにせ ldirectord の実サービス死活監視インターバルは通常数秒から数十秒とひっきりなしなのだ。
ひっきりなしの対策として、もうひとつ是非やっておきたいことがある。Apache の access_log が死活確認用コンテンツへのアクセス記録で溢れ返らないための対策だ。 httpd.conf に下記の設定を含める (あなたのApacheでは combined のところは common などかもしれない。適宜読み替えるべし);
SetEnvIf Request_URI "^\/hacheker/" nolog CustomLog logs/access_log combined env=!nolog
※ ただし、これは access_log に関してだけで、Apache には今のところ error_log に対してのこのようなフィルタリング手段は用意されていない。
上記では最も単純な例としてスタティックなHTMLファイルを死活確認用コンテンツとしたが、例えばこれら実サーバが Javaアプリケーションサービスやデータベースと不可分な業務を提供している場合には、Javaサーブレットや、データベースに対して簡単なクエリを行って結果に応じて文字列を返す php など、動的なコンテンツを死活確認コンテンツとして指定すればいい。実際、Tomcat の簡単なサーブレット (class) を作って動かした経験がある。
前出の ldirectord.cf ではログの書き出し先を local0 (logfile="local0") にしているので、それに合わせて /etc/syslog.conf に設定を追加する。
*.info:mail.none;authpriv.none;...;local0.none /var/log/messages local0.* /var/log/ultramonkey.log
反映は;
root# service syslog restart
当節は、heartbeat をまだ使わずに webserver1 でのみ ldirectord を動かしてみる時にだけ行う。
本来なら heartbeat がやってくれることなのだが、まだ heartbeat を実装する前なので、代わりに手動で VIP を発生させる。ここまでの説明を理解していれば自明のことだが、この処理を施すのは webserver1 だけだ。ループバックのエイリアスを作った時のように ifcfg-eth0:0 を作成してもいいのだが、せっかくなので heartbeat がやるのと同じように iproute2 の ip コマンドを使って登録することにする。ただし、マシンを再起動すればこのアドレスは消えてしまう。まあ、どのみち暫定処置であって、heartbeat を実装したらこれは削除しなくてはならない。
root# ip addr add 192.168.1.250/32 brd 192.168.1.255 dev eth0
一方、もしも heartbeat 抜きで ldirectord だけを恒久的に使いたいというのなら、通常やるように eth0 のエイリアスを webserver1 の /etc/sysconfig/network-scripts/eth0:0 ファイルで定義してやればいい。その時の記述例を挙げるなら下記のようになる。ただし、後で気が変わって heartbeat も使いたくなったら、その時はこのファイルを削除するのを忘れずに。
DEVICE=eth0:0 TYPE=Ethernet BOOTPROTO=static BROADCAST=192.168.1.255 IPADDR=192.168.1.250 NETMASK=255.255.255.255 NETWORK=192.168.1.0 ONBOOT=yes
この章では heartbeat はまだ使っていないので、ldirectord は heartbeat から呼び出されるのではなく自ら起動しなければならない。両 webserver で httpd を開始した後、webserver1 で ldirectord を起動させる;
root# service heartbeat stop (念のため) root# service ldirectord start
ldirectord だけを恒久的に機能させたい場合 (つまり前行程で ifcfg-eth0:0 を作った人) は、スタートアップ登録を調整する;
root# chkconfig --del heartbeat (両webserver とも) root# chkconfig ldirectord on (webserver1 のみ)
root# ipvsadm -L -n
ipvsadm コマンドを直接使用する以外に、JEDI にある解説 "How to install Ultra Monkey LVS in a 2-Node HA/LB Setup on CentOS/RHEL4" の中で挙げられている cluster というスクリプトを利用する手もある。それを少々修正したものを置いておく;
オリジナルとの違いは、ホスト名の使用されていたところを全て IP による指定に変えた点。
このスクリプトを /etc/init.d/ へパーミション root:root 700 でコピーし、以下のパラメータ調整を行う;
使い方:
#状態確認 root# service cluster status #指定の実サーバへの振り分けを止めさせる root# service cluster stop <実サーバIPアドレス> #指定の実サーバへの振り分けを再開 root# service cluster start <実サーバIPアドレス>
status では、heartbeat を使っていない現段階では出力の 1行目と 2行目はまだきちんと機能していない。
stop は、その実サーバを LVS から除去するわけではなく、ウェイトを 0 にすることによって振り分けされなくする (start はその逆)。ただし、stop しても、アクティブなコネクション (ActiveConn) または待機中のコネクション (InActConn) が解放されないうちは、当該クライアントからの要求はそれまでと同じ実サーバへ引き続き振り分けられる。
書いてある設定自体が間違っている場合は論外として、筆者が引っかかった、または引っかかりかけたトラブルを挙げておく。