Linux Virtual Server(LVS)プロジェクトは、レイヤ4スイッチングを利用して、Webサーバやメールサーバなどのネットワーク・サービスの負荷分散を可能にします。これは非常に高速で、これらのサービスは、数万から数十万もの同時接続にまで拡張してサービスを提供できるようになります。 このチュートリアルの目的は、LVSのさまざまな機能を利用してインターネット・サービスの負荷分散を行う方法と、heartbeatやkeepalivedなどのツールを使って高可用性を実現する方法を示すことです。さらに、高可用性環境でアクティブな接続を保持することや、アクティブなフィードバックを活用して負荷をより効果的に分散させることなど、最近の開発テーマとなっている高度なトピックも扱います。
Linux Virtual Server(LVS)プロジェクトは、Linuxカーネルにレイヤ4スイッチングを実装します。これにより、TCPとUDPのセッションの負荷をを複数の実サーバ間で分散できます。つまり、インターネット・サービスを1台以上のホストに拡張できるようになります。これは、電子メールからX Window Systemまで、ほとんどのサービスで利用できますが、World Wide WebへのHTTPとHTTPSのトラフィックで利用するのが最も一般的だと思われます。
LVS自体はLinux上で動作しますが、双方が利用しているOSに関係なく、エンドユーザから実サーバへの接続を負荷分散できます。接続がTCPまたはUDPのいずれかを使ってさえいれば、LVSを利用できます。
LVSは非常に高性能で、最高で10万もの同時接続を処理できます。飽和状態の100Mビットethernetリンクを、廉価なコモディティ・ハードウェアを使って簡単に負荷分散することができます。また、よりハイエンドなコモディティ・ハードウェアを使えば、飽和状態の1Gビット以上のリンクを負荷分散することも可能です。
このセクションでは、LVSの仕組み、LVSの入手およびインストール方法、主な動作モードの設定方法など、基本的な情報を扱います。この情報で、TCPとUDPサービスを負荷分散するようLVSを設定することができます。
Linux Director:LinuxとLVSがインストールされたホスト。エンドユーザからのパケットを受け取り、実サーバへ転送する。
エンドユーザ:接続の起点となるホスト。
実サーバ:接続の終点となるホスト。Apacheなど、何らかのデーモンを実行している。
単一のホストが、上記のうち複数の役割を同時に果たすこともある。
仮想IPアドレス(VIP):Linux Directorが扱うサービスに割り当てられるIPアドレス。
実IPアドレス(RIP):実サーバのIPアドレス。
レイヤ4スイッチングは、着信TCP/IP接続とUDP/IPデータグラムを実サーバに多重化することで機能します。パケットはLinux Directorが受け取り、どの実サーバに転送するかを決めます。これが決まると、同じ接続のこれ以降のパケットが同じ実サーバに送られます。このようにして接続の整合性が保たれます。
Linux Virtual Serverは、NAT(Network Address Translation)、IP-IPカプセル化(トンネリング)、ダイレクト・ルーティングの3通りの方法でパケットを転送できます。
Linux Directorでは、仮想サービスはIPアドレスとポートとプロトコル、またはファイアウォール・マークで定義されます。仮想サービスには、オプションで持続性タイムアウトを関連付けることができます。これが設定されており、タイムアウト時間が経過する前に同じIPアドレスから接続が着信すると、その接続は元の接続と同じ実サーバに転送されます。
仮想サービスには、着信接続を実サーバに割り当てるのに使用するスケジューリング・アルゴリズムが割り当てられます。LVSでは、スケジューラが別のカーネル・モジュールとして実装されています。そのため、LVSのコードを変更しなくても新しいスケジューラを実装できます。
スケジューリング・アルゴリズムは、用途に合わせてさまざまなものがあります。最もシンプルなのはラウンドロビンと最小コネクションです。ラウンドロビンは、各実サーバに順々に接続を割り当てます。最小コネクションは、最も接続数が少ない実サーバに接続を割り当てます。どちらも単純な仕組みで機能します。これらのスケジューラには負荷に応じて割り当てを行う変種もあり、これらにおいては、実サーバの負荷に比例して接続が割り当てられます。よりスペックの高い実サーバに負荷を多く設定しておけば、より多くの接続が割り当てられる仕組みです。
特別な用途に対応した、もっと複雑なスケジューリング・アルゴリズムもあります。たとえば、同じIPアドレスの要求が同じ実サーバに転送されるようにするものは、透過プロキシの負荷分散にLVSを利用する際に役立ちます。
SuSEなど一部のディストリビューションは、LVSがコンパイルされたカーネルを備えています。この場合に必要となる作業は、提供されているipvsadmパッケージをインストールすることだけです。本稿の執筆時点では、Ultra MonkeyはDebian Sid(不安定版)、Woody(安定版/3.0)、そしてRed Hat 7.3と8.0向けにビルドされたパッケージを用意しています。これらのパッケージの入手とインストールについての詳しい情報は、www.ultramonkey.orgを参照してください。以降では、ソースからLVSをインストールする方法を解説します。これは、LVSの仕組みを理解するのにも役立つはずです。
初期バージョンのLVSは、Linux 2.2シリーズのカーネルで動作していました。この実装では、カーネル・ソースに多くのパッチを当てる必要がありました。このため、各バージョンのLVSはカーネルのバージョンに密接に結びついていることになります。2.4カーネルの一部であるnetfilterパケット・フィルタリング・アーキテクチャ[4]は、LVSを一連のカーネル・モジュールとしてほとんど単独で実装することを可能にします。この結果、LVSが個々のカーネル・リリースに固定されてしまうことがなくなります。LVSはカーネルに直接コンパイルすることもできますが、ここではより簡単で柔軟な、LVSをモジュールとして利用する方法を扱います。
すべての場合において最も簡単なのは、フレッシュなカーネルを使うことです。これはwww.kernel.orgから入手できます。この例で使用するのは2.4.20カーネルです。次のコマンドを実行し、カーネルをlinux-2.4.20ディレクトリにアンパックします。
tar -jxvf linux-2.4.20.tar.bz2
LVSは、www.linuxvirtualserver.orgから入手できます。この例では1.0.9を使います。次のコマンドを実行して、ipvs-1.0.9ディレクトリにアンパックします。
tar -zxvf ipvs-1.0.9.tar.gz
LVSモジュールをコンパイルするには、2つの小さなカーネル・パッチが必要です。これらのパッチを適用するには、次のコマンドを使います。
cd linux-2.4.20/ patch -pq < ../ipvs-1.0.9/linuxkernel_ksyms_c.diff patch -pq < ../ipvs-1.0.9/linuxnet_netsyms_c.diff
インターフェイスを隠せるように、3つ目のパッチを適用します。隠れインターフェイスはARP要求に応答せず、LVSダイレクト・ルーティングと共に実サーバで使われます。
patch -pq < ../ipvs-1.0.9/contrib/patches/hidden-2.4.20pre10-1.diff
まず、ツリーがクリーンであることを確認します。
make mrproper
それでは、カーネルを構成していきます。make menuconfig、make xconfig、make configなどさまざまな方法がありますが、いずれの方法においても、最低でも次のオプションを含めて、netfilterサポートでコンパイルするよう注意してください。これらのオプションはできるだけモジュールとしてビルドすることをお勧めします。
Networking options ---> Network packet filtering (replaces ipchains) <m> IP: tunnelling IP: Netfilter Configuration ---> <m> Connection tracking (required for masq/NAT) <m> FTP protocol support <m> IP tables support (required for filtering/masq/NAT) <m> Packet filtering <m> REJECT target support <m> Full NAT <m> MASQUERADE target support <m> REDIRECT target support <m> NAT of local connections (READ HELP) (NEW) <m> Packet mangling <m> MARK target support <m> LOG target support
カーネルを再構成したら、ビルドの依存関係を再構築する必要があります。
make dep
これが済んだら、次のコマンドを使ってカーネルとモジュールをビルドします。
make bzImage modules
ビルドされたモジュールとカーネルをインストールするには、次のコマンドを実行します。これにより、/lib/modules/2.4.20/にモジュールがインストールされ、/boot/vmlinuz-2.4.20にカーネルがインストールされます。
make install modules_install
ブート・ローダにgrubを使っている場合、/etc/grub.confに新しいエントリを追加する必要があります。ここでは、/bootパーティションが/dev/hda3であることを前提に説明します。/etc/grub.conf内の既存のエントリを参考にしてください。
title 2.4.20 LVS root (hd0,0) kernel /vmlinuz-2.4.20 ro root=/dev/hda3
ブート・ローダがliloの場合、/etc/lilo.confに新しいエントリを追加します。ここでは、ルートパーティションが/dev/hda2であることを前提に説明します。/etc/lilo.conf内の既存のエントリを参考にしてください。
image=/boot/vmlinuz-2.4.20 label=2.4.20-lvs read-only root=/dev/hda2
/etc/lilo.confがアップデートされたら、liloを実行します。
lilo Added Linux-LVS * Added Linux Added LinuxOLD
ブート・ローダのプロンプトで、新しく作成したカーネルがブートしていることを確認します。
LVSをビルドするためのコマンドは、ipvs-1.0.9/ipvs/ディレクトリから実行します。ビルドとインストールに使うコマンドは次のとおりです。カーネルをビルドした/kernel/source/linux-2.4.20をルート・ディレクトリとして使用してください。
make KERNELSOURCE=/kernel/source/linux-2.4.20 all make KERNELSOURCE=/kernel/source/linux-2.4.20 modules_install
Ipvsadmは、LVSの設定に使用するユーザ空間ツールです。ソースはipvs-1.0.9/ipvs/ipvsadm/ディレクトリにあります。ビルドとインストールには次のコマンドを使います。
make all make install
LVS NATは、LVSを設定するおそらく最も単純な方法でしょう。実サーバからのパケットをLinux Directorが受け取り、送信先IPアドレスが実サーバのものに書き換えられます。実サーバからの返信パケットの送信元IPアドレスは、実サーバの物からVIPのものに変わります。
net.ipv4.ip_forward = 1
ifconfig eth0:0 172.17.60.201 netmask 255.255.0.0 broadcast 172.17.255.255
ipvsadm -A -t 172.17.60.201:80 ipvsadm -a -t 172.17.60.201:80 -r 192.168.6.4:80 -m ipvsadm -a -t 172.17.60.201:80 -r 192.168.6.5:80 -m
テストは、サーバ・ネットワークの外部から172.17.60.201:80に接続して行います。
Linux Directorと実サーバでパケット・トレースのツールを実行するとデバッグに非常に役立ちます。接続パスをトレースし、どの段階でパケットが消えているかを判断すれば、設定に関する多くの問題を解決できます。ここでは、例としてTcpdumpを使う方法を紹介しますが、さまざまなOS向けに数多くのツールが存在します。
次のトレースでは、エンドユーザ10.2.3.4がVIP 172.17.60.201への接続を開始し、この接続が実サーバ192.168.6.5に転送されています。Linux Directorがパケットを受け取って実サーバに転送し、またその逆が行われているのがわかります。実サーバに転送されたパケットが、送信元アドレスとしてエンドユーザのIPアドレスを持っていることに注目してください。Linux Directorが変更するのは、パケットの送信先IPアドレスだけです。同様に、実サーバからの返信にも、送信先としてエンドユーザのアドレスが指定されています。Linux Directorは返信パケットの送信元IPアドレスだけをVIPになるように書き換えます。
tcpdump -n -i any port 80 12:40:40.965499 10.2.3.4.34802 > 172.17.60.201.80: S 2555236140:2555236140(0) win 5840 <mss 1460,sackOK,timestamp 16690997 0,nop,wscale 0> 12:40:40.967645 10.2.3.4.34802 > 192.168.6.5.80: S 2555236140:2555236140(0) win 5840 <mss 1460,sackOK,timestamp 16690997 0,nop,wscale 0> 12:40:40.966976 192.168.6.5.80 > 10.2.3.4.34802: S 2733565972:2733565972(0) ack 2555236141 win 5792 <mss 1460,sackOK,timestamp 128711091 16690997,nop,wscale 0> (DF) 12:40:40.968653 172.17.60.201.80 > 10.2.3.4.34802: S 2733565972:2733565972(0) ack 2555236141 win 5792 <mss 1460,sackOK,timestamp 128711091 16690997,nop,wscale 0> (DF) 12:40:40.971241 10.2.3.4.34802 > 172.17.60.201.80: . ack 1 win 5840 <nop,nop,timestamp 16690998 128711091> 12:40:40.971387 10.2.3.4.34802 > 192.168.6.5.80: . ack 1 win 5840 <nop,nop,timestamp 16690998 128711091> ctrl-c
アクティブな接続の数を表示するには、ipvsadm -L -nを使います。
ipvsadm -L -n IP Virtual Server version 1.0.9 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.17.60.201:80 rr -> 192.168.6.5:80 Masq 1 7 3 -> 192.168.6.4:80 Masq 1 8 4
ipvsadm -L -statsは、1秒間に送信および受信されるパケットの数とバイト数を表示します。
ipvsadm -L -n --stats IP Virtual Server version 1.0.9 (size=4096) Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes -> RemoteAddress:Port TCP 172.17.60.201:80 114 1716 1153 193740 112940 -> 192.168.6.5:80 57 821 567 94642 55842 -> 192.168.6.4:80 57 895 586 99098 57098
ipvsadm -L -rateは、送信および受信されるパケットの合計数を表示します。
ipvsadm -L -n --rate IP Virtual Server version 1.0.9 (size=4096) Prot LocalAddress:Port CPS InPPS OutPPS InBPS OutBPS -> RemoteAddress:Port TCP 172.17.60.201:80 56 275 275 18739 41283 -> 192.168.6.5:80 28 137 137 9344 20634 -> 192.168.6.4:80 28 138 137 9395 20649
ipvsadm -L -zeroは、全統計情報の値をゼロにします。
LVSダイレクト・ルーティングは、パケットを変更せずに、実サーバのMACアドレスに転送することで機能します。パケットが変更されないので、VIP宛てのトラフィックを受け入れるよう実サーバを設定しておく必要があります。これは、隠れインターフェイスを使って実現されるのが一般的です。
Linux Directorは着信パケットを変更しないので、返信パケットがLinux Directorを経由する必要はありません。このおかげで、より高いスループットを実現できます。さらに、返信パケットがLinux Directorを経由せず直接エンドユーザに送られるので、同じローカル・ネットワーク内のエンドユーザに対してサービスを負荷分散するのが容易になります。
net.ipv4.ip_forward = 1
ifconfig eth0:0 172.17.60.201 netmask 255.255.0.0 broadcast 172.17.255.255
ipvsadm -A -t 172.17.60.201:80 ipvsadm -a -t 172.17.60.201:80 -r 172.17.60.199:80 -g ipvsadm -a -t 172.17.60.201:80 -r 172.17.60.200:80 -g
しかし、場合によっては(Linux Directorが、本当に実サーバのネットワークのゲートウェイである場合など)、実サーバからの返信パケットをLinux Director経由でルーティングすることが望ましいこともあります。このようなパケットの送信元アドレスはVIPになります。ただし、このVIPはLinux Directorのインターフェイスに属しているので、Linux Directorはパケットが偽造されていると見なしてこれを破棄してしまいます。
この問題を解決する方法はいくつかあります。最もよいのは、Julian Anastasov提供のカーネル・パッチを適用することです。このパッチは、インターフェイスごとにパケット破棄の動作を無効にすることができるprocエントリを追加します。このパッチはhttp://www.ssi.bg/~ja/#lvsgwから入手できます。
ifconfig lo:0 172.17.60.201 netmask 255.255.255.255
172.17.60.201が属するネットワークの実際のネットマスクに関係なく、ネットマスクは255.255.255.255でなければなりません。これは、ループバック・インターフェイスでは、ネットマスクがカバーするすべてのアドレスがインターフェイスにバインドされているからです。よくあるケースは、127.0.0.1、ネットマスク255.0.0.0で設定されたループバック・インターフェイスが127.0.0.0/8のトラフィックをすべて受け入れるというものです。したがって、ここではlo:0だけが172.17.60.201宛てのパケットを受け取るようにしたいので、ネットマスクが255.255.255.255である必要があるのです。
# 隠れデバイスの設定を有効にする net.ipv4.conf.all.hidden = 1 # ループバック・インターフェイスを隠す net.ipv4.conf.lo.hidden = 1
テストは、任意のネットワークから172.17.60.201:80に接続することで行えます。
デバッグは、LVS NATと同様に、ipvadmとパケット・トレースを使って行えます。ただし、パケットが転送される際に、アドレス変換が行われないことに注意してください。また、返信パケットがLVSによって処理されないことにも注意が必要です。実サーバからエンドユーザに直接送られます。よって、送信パケットとそのバイト数はゼロになります。
LVSトンネリングは、ダイレクト・ルーティングとほぼ同じ仕組みです。主な相違点は、単に新しいethernetフレームを送るのではなく、IPにカプセル化されたIPを使ってパケットが実サーバに転送されることです。この最大のメリットは、実サーバがLinux Directorとは別のネットワーク上にあっても構わないということです。
net.ipv4.ip_forward = 1
ifconfig eth0:0 172.17.60.201 netmask 255.255.0.0 broadcast 172.17.255.255
ipvsadm -A -t 172.17.60.201:80 ipvsadm -a -t 172.17.60.201:80 -r 172.17.60.199:80 -i ipvsadm -a -t 172.17.60.201:80 -r 172.17.60.200:80 -i
「ダイレクト・ルーティング」のセクションで紹介したパッチをカーネルに適用していない場合は、返信パケットがLinux Director経由でルーティングされていないことを確認します。
ifconfig tunl0 172.17.60.201 netmask 255.255.255.255
net.ipv4.ip_forward = 1 # 隠れデバイスの設定を有効にする net.ipv4.conf.all.hidden = 1 # tunl0インターフェイスを隠す net.ipv4.conf.tunl0.hidden = 1
テストは、任意のネットワークから172.17.60.201:80に接続することで行えます。デバッグはLVSダイレクト・ルーティングの場合と同様です。
LVSは、ネットワーク・サービスの負荷分散を効率的に行うための方法です。一般的には、複数のサーバが(エンドユーザから見て)1つのサーバであるかのように動作することを意味します。残念ながら、システム内のサーバの数が増えれば増えるほど、そのうちの1台に障害が起きる可能性も高くなります。したがって、高可用性を実現するテクニックを利用して、1台のサーバに障害が起きても仮想サービスが保持されるようにすることが重要です。
Heartbeatは、1組のLinux Directorを監視するのに使われ、すべてのタイミングでその一方にVIPが割り当てられていることを保証するものです。これは、各ホストが定期的にheartbeatメッセージを送信することで機能します。決められた時間内にheartbeatメッセージが受け取られないと、そのホストに障害が起きたと見なされます。この場合、リソースをテイクオーバーすることができます。Heartbeatはモジュール式の設計になっており、任意のリソースを定義することができます。
説明の都合上、ここではIPアドレスをリソースとします。フェイルオーバーが起きると、IPアドレス引継ぎと呼ばれる方法でIPアドレスが取得されます。これは、新しくアクティブになったLinux Directorがgratuitous ARPパケットをVIPに送信することで行われます。ネットワーク内のすべてのホストは、これらのARPパケットを受け取り、以降のパケットを新しいLinux DirectorのVIPに宛てて送ります。
Heartbeatはwww.linux-ha.orgから入手できます。提供されているパッケージを使ってインストールするか、次のコマンドを使ってソースからビルドします。
./ConfigureMe build make make install
/etc/ha.dにある3つのファイルを使って、設定を行います。
logfacility local0 keepalive 2 deadtime 10 warntime 10 initdead 10 nice_failback on mcast eth0 225.0.0.7 694 1 1 node walter node wendy
walter 172.17.60.201/24/eth0
auth 2 2 sha1 ultramonkey
LVSは両方のLinux Directorで同じように設定します。この例では、すでに説明したLVSトンネルの設定を使いますが、ダイレクト・ルーティングとNATを使うこともできます。
VIPとしては、172.17.60.201はheartbeatによって管理されているので、その他の目的でLinux Directorに設定してはなりません。
Heartbeatを両方のLinux Directorで開始します。しばらくすると、マスタであるLinux DirectorにVIPが割り当てられます。
アクティブなLinux Directorを再起動して、ほかのLinux Directorがテイクオーバーを行うことを確認します。テイクオーバーの進行状況は、syslogに送られたログ(通常、/var/log/messages)で確認できます。nice_failbackがオンなので、現在アクティブなLinux Directorがマスタとして機能し、障害が起きたLinux Directorが復旧すると、スタンバイとして機能します。
heartbeatの設計は、ホストが利用可能な通信チャネルがあれば、そのホストが利用可能だと見なすようになっています。この動作が望ましくない場合もあります。たとえば、1組のホストが内部ネットワークと外部ネットワークの両方にリンクを持っている場合、片方のホストのどちらかのリンクが切れた場合(つまり、エンドユーザと実サーバとの間でトラフィックをルーティングできなくなった場合)に、フェイルオーバーを行った方がよいでしょう。
heartbeat用のipfailプラグインは、1台以上のpingノードと呼ばれる外部ホストを監視することでこれを可能にします。通常これは、ルータまたはスイッチそのものです。pingノードは定足数デバイスとして扱われます。つまり、ホストがpingノードにアクセスできなくなると、リソースを確保する権利がなくなります。このように、アクティブなLinux Director上のインターフェイスに障害が起きると、いずれかのpingノードが利用不可能になり、フェイルオーバーが起こります。
The ipfailモジュールは、heartbeatの一部として提供されています。詳細情報はhttp://pheared.net/devel/c/ipfail/を参照してください。この情報は、将来的にheartbeatのマニュアルに収められるでしょう。
前述のheartbeatの設定でipfailを利用するには、heartbeatのha.cfファイルに次の行を追加する必要があります。
ping 172.17.0.254 respawn hacluster /usr/lib/heartbeat/ipfail
各pingノードに、pingディレクティブを追加します。この例では、内部ネットワークには適切な定足数デバイスがなかったので、外部ネットワークに1つだけpingノードを設定しました。
respawnディレクティブは、ユーザhaclusterとして/usr/lib/heartbeat/ipfailを実行するようheartbeatに指示します。ステータスが100以外である場合にipfailを再試行するため、また、heartbeatが存在する場合にipfailを停止するために使います。
これらのオプションを追加したら、heartbeatを再起動します。
/etc/init.d/heartbeat restart
テストとデバッグは、Heartbeat自体の場合と同じように行います。
Heartbeatは、Linux Directorの健康状態を監視するのに使われます。Ldirectordは、実サーバの健康状態を監視し、LVSカーネル・テーブルを適切に操作します。Ldirectordとheartbeatは、高可用性のLVSクラスタを実現するためにしばしば組み合わせて利用されます。
Ldirectordは実サーバに接続して、実サーバ上のサービスをチェックし、既知の要求を行って、その結果に既知の文字列が含まれるかどうかをチェックします。チェックを行える対象は、HTTP、HTTPS、FTP、IMAP、POP、SMTP、LDAP、NNTPです。コードを変更すれば(通常は非常に単純な作業です)、その他のチェックを追加することも可能です。実際、ldirectordに組み込まれているチェックの大多数は、ユーザによってパッチとして提供されたものなのです。
上記のようなチェックのセマンティクスは、ネゴシエート・チェックと呼ばれます。もう1つのチェック方法である接続チェックは、実サーバ上のサービスに対して接続をオープンできるかどうかだけをチェックします。これは、ldirectordでチェックが提供されていないプロトコルをチェックするのに役立ちます。
Ldirectordは、ldirectord.cfファイルで設定します。このファイルに含まれるグローバル・ディレクティブは、エラーログの記録場所などのグローバルなオプションを設定するか、または仮想サービスのデフォルトに従います。仮想サービスは、LVSによって提供される仮想サービスをカプセル化します。この仮想サービスには、チェックされる実サーバが含まれます。
# グローバル・ディレクティブ checktimeout=10 checkinterval=2 autoreload=no logfile="local0" quiescent=yes # HTTPの仮想サーバ virtual=172.17.60.201:80 fallback=127.0.0.1:80 real=192.168.6.4:80 masq real=192.168.6.5:80 masq service=http request="index.html" receive="Test Page" scheduler=rr protocol=tcp checktype=negotiate
Ldirectordは、ldirectordコマンドまたはldirectord initスクリプトを実行するか、もしくはheartbeatのリソースとして追加することで開始できます。最後の方法には特別なメリットがあるわけではありません。ldirectordは、マスタLinux DirectorとスタンバイLinux Directorの両方で、問題なく同時稼働できます。
ldirectordが開始されると、LVSカーネル・テーブルに値が入力されます。
ipvsadm -L -n IP Virtual Server version 1.0.7 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.17.60.201:80 rr -> 192.168.6.5:80 Masq 1 0 0 -> 192.168.6.4:80 Masq 1 0 0 -> 127.0.0.1:80 Local 0 0 0
デフォルトでは、ldirectordはLVSの休止機能を利用して実サーバを追加したり削除したりします。つまり、実サーバを削除するときには、そのウェイトがゼロに設定され、仮想サービスの一部ではあり続けます。これにより、実サーバへの既存の接続を継続しつつ、新規の接続は割り当てられないようにすることができます。これにより、既存の接続に影響を与えることなく実サーバをオフラインにすることができます。この動作は、グローバル設定オプションquiescent=noをセットして、仮想サービスから実サーバを削除することで変更できます。
テストは、実サーバをオンラインにしたりオフラインにしたりするか、要求されている既知のURLのコンテンツを変更する(期待されている文字列を取り除く)か、エンドユーザの要求を処理するデーモンを停止するか、すべてのホストの電源を同時に落とすことで行います。
いずれの場合にも、ldirectordはLVSカーネル・テーブルを適切にアップデートするはずです。これはipvsadm -L -nで検証できます。Ldirectordはさらにその動作をログに記録します。上記の設定では、これらのログはsyslog(通常は/var/log/syslogにあります)に書き込まれます。
デバッグ用のより詳細な情報が必要な場合は、ldirectordをデバッグ・モードで実行することができます。この場合、詳細なログがターミナルに出力され、ldirectordがターミナルから切り離されることはありません。これは、コマンドライン・オプション-dを使って行います。この例では、/etc/ha.d/にある設定ファイルldirectord.cfを使い、ldirectordをデバッグ・モードで実行しています。デバッグはctrl-cで終了できます。
ldirectord -d ldirectord.cf start
Keepalivedは、RFC 2338[1]で定義されるVRRPv2プロトコルを実装します。VRRPv2は、ネットワーク上の特定のVIPが一度に1つのホストにのみ割り当てられるよう制御する方法です。これは、アクティブ/スタンバイLinux Directorを切り替えるのに利用できます。
VRRPv2は、単純な状態エンジンで機能します。ホストは自らの利用可能状況をアドバタイズし、最も優先順位の高いホストにリソースが割り当てられ、そのホストはその事実をアドバタイズします。すると、ほかのすべてのノードがバックアップ状態になります。
VRRPv2のLinux向け実装としては、http://off.net/~jme/vrrpd/で提供されているものもありますが、本稿の執筆時点では、keepalivedの実装のほうがずっと充実しています。
Keepalivedでは、実サーバをサービスレベルで監視して、LVSカーネル・テーブルを適切に操作することもできます。実装されているサービスのテストは次のとおりです。
新しいチェック項目を追加するためのAPIも提供されています。
VRRPDとLVS/Health-Check機能は、個別に使うことも、組み合わせて使うこともできます。
Keepalivedは、keepalived.sourceforge.netから入手できます。コンパイルは非常に単純で、./configureとmakeで行います。Red Hat用の.specファイルも提供されています。Debian用のパッケージはDebianのmainツリーから入手できます。
keepalivedの設定には、/etc/keepalived/keepalived.confを変更します。このファイルは2つの部分から構成されています。
VRRP実装はマスタ/スレーブシステムで動作するということに注意してください。このため、2つのvrrp_instanceは、一方では"MASTER"として、他方では"SLAVE"としてマークする必要があります。テストでは、heartbeatのnice_failbackと同様の動作をするようにkeepalivedを設定することはできないことが判明しました。nice_failbackは、1つのノードが、障害が起きるまでリソースを保持し、障害が起きるとほかのノードがそのリソースを引き継ぐというものです。また、偽のフェイルオーバーを防ぐために、スレーブ・ノードの優先度はマスタ・ノードよりも低くしておくべきだということもわかりました。
スペースの都合上、設定ファイルの例は付録Aに収録されています。
設定ファイル用のチェックサムを作成するには、genhashプログラムを使います。genhashは、サーバに接続してURLを要求し、大量の出力(チェックサムの作成に使われたデータ)を生成します。最後の行は、keepalived.confに含まれるチェックサムです。たとえば、http://192.168.6.5:80/というURLのハッシュを生成するには、次のコマンドを使います。
genhash -s 192.168.6.5 -p 80 -u / [ 出力の大部分を省略 ] 90bfbce6bc089a41f1fddca9aeaba452
keepalivedを開始するには、keepalivedデーモンかinitスクリプトを実行します。メッセージはsyslog(通常は/var/log/message)にログ記録されます。しばらくすると、両マシンのLVSカーネル・テーブルに値が入力されます、これは、ipvsadmを使って検証できます。
ipvsadm -L -n IP Virtual Server version 1.0.7 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.17.60.201:80 lc -> 192.168.6.5:80 Masq 1 0 0 -> 192.168.6.4:80 Masq 1 0 0
マスタ・マシンでは、仮想IPアドレスを追加する必要があります。これをチェックするにはipコマンドを使います。
ip addr sh [ lo: 省略 ] 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo\_fast qlen 100 link/ether 00:50:56:4f:30:19 brd ff:ff:ff:ff:ff:ff inet 172.17.60.207/16 brd 172.17.255.255 scope global eth0 inet 172.17.60.201/32 scope global eth0 3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo\_fast qlen 100 link/ether 00:50:56:4f:30:1a brd ff:ff:ff:ff:ff:ff inet 192.168.6.3/24 brd 192.168.6.255 scope global eth1 inet 192.168.6.1/32 scope global eth1
フェイルオーバーが起きると、同じアドレスがスレーブに表示されるようになります。このアドレスは、マスタが復旧するとマスタに戻ります。
Ldirectordやkeepalivedなどのツールは、実サーバの健康状態を監視します。weightパラメータを使うことで、実サーバの相対的な処理能力を考慮に入れることができます。ただし、これらのツールはリアルタイムで実サーバのサービス提供能力をモニタするだけで、それに応じて接続を割り当てることはしません。
これは、一部の接続がほかの接続よりも実サーバ上のリソースを多く必要とするような場合に、特に問題になります。たとえば、ディスク(またはメモリ)からプレーンなHTMLファイルを取得するだけの接続と、画像をスケーリングしたり、データベースからページの一部を取り出したりするような、処理動作が伴う接続がある場合などです。
Feedbackdは、それぞれの実サーバのリアルタイムの情報を基に、相対的にどれだけの接続を割り当てるべきかを判断できるフレームワークを実装します。これが、feedbackdのアクティブ・フィードバック・システム実装です。feedbackdはhttp://www.redfishsoftware.com.au/projects/feedbackd/から入手できます。
Feedbackdには2つの主要コンポーネントがあります。feedbackd-agentは、実サーバ上で動作し、サービス提供能力を監視します。この監視はモジュール式なので、任意のチェックを定義することができます。デフォルトで提供されているチェックは、/proc/statを使ってCPU負荷を監視するだけです。もう1つのコンポーネントであるfeedbackd-masterは、Linux Director上で動作します。接続されているfeedbackd-agentからの情報を照合し、それに応じてLVSカーネル・テーブル内の実サーバのウェイトを操作します。
コンパイルには少々工夫が必要でした。また、「address in use」エラーを発生させずにfeedbackd-masterを再起動できるように、また、feedbackd-agentがmasterをタイムアウトさせることができるようにするための拡張を行いました。後者は、feedbackdをアクティブ/スタンバイ構成のLinux Directorでも利用できるようにするための対策です。これらの変更は作者に伝えてあるので、次のバージョンに反映されることを期待しています。
feedbackd-masterで必要な設定は、利用するLVS仮想サービスを確立することだけです。これは、ipvsadmを使って行うことができます。実サーバの追加は、feedbackd-masterが実サーバで動作しているfeedback-agentから提供されたプロトコル情報とポート情報を照合して行うので、こちらで行う必要はありません。このように、feedbackdを利用すると、Linux Directorを一切設定せずに、実サーバの追加と削除をその場で行うことができます。次に例を示します。
ipvsadm -A -t 172.17.60.201:80
feedbackd-masterを開始するには、コマンドラインからデーモンを実行します。現時点のディストリビューションではinitスクリプトは提供されていません。
Feedbackd-Agentの設定は、/etc/feedbackd-agent.confを変更することで行います。このファイルには、feedbackd-masterを実行しているLinux Directorと、実サーバが加わるべきサービスを指定します。
director = 192.168.6.1 service = http protocol = TCP port = 80 module = cpuload.so forwarding = NAT
feedbackd-agentを開始するには、コマンドラインからコマンドを実行します。
最初のテストとして、実サーバのうち1台を手動でロードして、この操作がLinux Director上のLVSテーブルにどのような影響を与えるかをipvsadmを使って確認します。Jeremy Kerrによるfeedbackdについてのペーパー[3]に、feedbackdを利用した場合の効果に関する詳しい分析があります。
2台のLinux Directorをアクティブ/スタンバイ構成で利用するのは、高可用性を実現するうえで有用です。アクティブなLinux Directorに障害が起きると、スタンバイが仮想サービスのIPアドレスを自動的に引き継ぐので、クラスタの機能が保持されます。しかし、このようなフェイルオーバーが起きると、現在の接続は切断されます。
これは、スタンバイLinux Directorがこれらの接続についての情報を何も持たないためです。アクティブLinux DirectorとスタンバイLinux Directorとの間で接続情報を同期化することで、この問題を解決できます。すなわち、スタンバイLinux Directorがアクティブになったときに、現在アクティブな接続についての情報を得ることで、パケットの転送を引き続き行うことができるということです。ここで重要なのは、特定の接続のパケットをどの実サーバに転送すべきかという情報です。この情報は非常にサイズが小さいので、同期化のオーバーヘッドは少なくてすみます。
現行のLVSコードには、接続の同期化が実装されています。これは、マスタ/スレーブシステムで機能します。マスタとして設定されたLinux Directorは接続の同期化情報を送信し、スレーブとして設定されたLinux Directorは、この情報を受け取って、LVSコネクション・テーブルを適切にアップデートします。
パケットの数がしきい値(3)を超えると、決まった頻度(50パケット)で接続が同期化されます。接続の同期化情報はキューに加えられ、定期的にフラッシュされます。1つのパケットに、最大で50の接続に関する同期化情報を含めることができます。このパケットはマルチキャストを使ってスレーブに送られます。
マスタとスレーブにおける同期化情報の送信/受信は、カーネル・スレッドによって行われます。カーネル同期化スレッドをマスタとスレーブで開始するには、次のコマンドを使います。
ipvsadm --start-daemon master # マスタLinux Directorで開始 ipvsadm --start-daemon backup # スレーブLinux Directorで開始
接続の同期化は、LVSコネクション・テーブルを一覧表示するipvsadm -L -c -nを使って監視することができます。接続はまずマスタLinux Directorに現れます。しばらくすると同期化が行われ、この接続がスレーブにも現れます。
ipvsadm -L -c -n # マスタLinux Director IPVS connection entries pro expire state source virtual destination TCP 01:00 TIME_WAIT 172.16.4.222:34939 172.17.60.201:80 192.168.6.5:80 TCP 01:01 TIME_WAIT 172.16.4.222:34940 172.17.60.201:80 192.168.6.4:80 TCP 15:00 ESTABLISHED 172.16.4.222:34941 172.17.60.201:80 192.168.6.5:80
ipvsadm -L -c -n # スレーブLinux Director IPVS connection entries pro expire state source virtual destination TCP 01.20 ESTABLISHED 172.16.4.222:34939 172.17.60.201:80 192.168.6.5:80 TCP 01.23 ESTABLISHED 172.16.4.222:34940 172.17.60.201:80 192.168.6.4:80 TCP 08.99 ESTABLISHED 172.16.4.222:34941 172.17.60.201:80 192.168.6.5:80
この出力では、マスタLinux Director上の2つの接続がTIME_WAIT状態(エンドユーザによって閉じられた)になっていることがわかります。さらに、1つの接続がESTABLISHED状態(エンドユーザと実サーバとの間に開かれている接続がある)になっています。
これらの接続はいずれもスレーブに同期化されます。注意してほしいのは、スレーブではすべての接続がESTABLISHED状態になることです。これは、ESTABLISHED状態にある接続だけが同期化されるよう、LVSコードが最適化されているためです。スレーブでは接続の状態は重要ではないので、これにより、不要な同期化のオーバーヘッドを排除できます。
各Linux Directorに次のiptables規則を追加すれば、さらに、どのLinux Directorが接続を処理しているかを監視することができます。
iptables -A INPUT -d 172.17.60.201 -j ACCEPT
これは、iptables -L INPUT -v -nを使って監視できます。
iptables -L INPUT -v -n # アクティブLinux Director Chain INPUT (policy ACCEPT 1553 packets, 211K bytes) pkts bytes target prot opt in out source destination 5 1551 ACCEPT all -- * * 0.0.0.0/0 172.17.60.201
iptables -L INPUT -v -n # スタンバイLinux Director Chain INPUT (policy ACCEPT 2233 packets, 328K bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 172.17.60.201
接続の同期化が正しく機能しているかどうかをテストするには、マスタLinux Directorがアクティブなときに、仮想サービスに対する接続を開きます。続いてフェイルオーバーを起こします。これには、マスタLinux Directorの電源を切るなどさまざまな方法が使えます。この時点で、接続は立ち往生します。VIPがスレーブLinux Directorにフェイルオーバーすると、接続は継続できます。
ストリーミングはこのテストに役立ちます。ストリーミングでは、その性質上、接続が長時間開かれているからです。さらに、動画や音楽が停止し、その後再開されるという、直感的なフィードバックを得ることができます。ただし、ストリーミングのクライアント・ソフトウェアでバッファ・サイズを大きくすると、このポーズが観察されなくなる可能性があるので注意が必要です。
この実装の主な問題点は、マスタ/スレーブという関係です。マスタLinux Directorに障害が起き、その後再びオンラインになると、スレーブの接続はマスタには同期化されません。次にフェイルオーバーが起きると、接続が切断されてしまいます。これを防ぐには、フェイルオーバーが起きたときにマスタとバックアップのデーモンを開始および停止するという方法が考えられますが、同期化デーモン間にピアツーピア関係を構築するほうがすっきりするでしょう。
この状況を改善するために、筆者はLVS用の新しい同期化デーモンを作成しました。これは、どのノードも同期化情報を送信および受信できるようなピアツーピア構成で動作します。
新しい同期化デーモンは、カーネルではなくユーザ空間で動作します。情報はカーネル内のLVSからnetlinkソケット経由で受け取ります。その後この情報はマルチキャストUDPを使って他のノードに送られます。マルチキャスト上の情報を受信すると、デーモンはnetlinkソケット経由でカーネル内のLVSにこの情報を送信して、このプロセスを逆転させます。
コードをユーザ空間に移すというアイデアは、より高度な同期化処理を可能にするためのものです。これは、カーネルよりもユーザ空間においてのほうが、より簡単で、さまざまな点でより適切に実装することができます。同期化が特に重要なタスクでない限り、これをカーネル内で行うことにメリットはありません。
コードには次のものが含まれます。
これはwww.ultramonkey.orgから入手可能です。
これは新しいコードなので、インストールとコンパイルには少々注意が必要です。また、サポート・ライブラリが多数必要になります。ビルドしたら、ipvsadm -stop-daemonを使ってLVSカーネルの同期化デーモンが実行されていないことを確認します。その後、コマンドラインから、またはip_vs_user_sync_simple initスクリプトを使って、ユーザ空間のデーモンを開始します。
ip_vs_user_sync_simpleのデバッグ・メッセージはデフォルトでsyslogに送られ、通常/var/log/messagesに書き込まれます。デーモンが正常に機能していない場合は、debugオプションを有効にして実行し、ターミナルにメッセージを表示することをお勧めします。これは、ip_vs_user_sync_simple.confを変更するか、コマンドラインから行えます。
ip_vs_user_sync_simple --debug --log_facility -
テストは、すでに説明した既存の接続同期化コードのテストと同様に行います。ただし、こちらの実装にはマスタ/バックアップという関係がないので、複数のフェイルオーバーを通じて接続を保持できます。
アクティブ/スタンバイLinux Directorは、高可用性を実現する優れた方法です。しかし、Linux Directorがダウンしたり、メンテナンスのためにオフラインになったりする頻度が低ければ、片方のLinux Directorはほとんどの時間アイドル状態になり、リソースを無駄に使うことになります。また、ネットワークの最大スループットが、Linux Directorのスループットに制限されてしまいます。
Active-Active構成のLinux Directorでは、1台以上のLinux Directorが、同じ仮想サービスの接続の負荷分散を同時に行うことができるので、この問題を解決できます。
筆者は、次のように動作するようこれを実装しました。
Saruは、コマンドラインから直接実行するか、独自のinitスクリプトを使って実行します。メッセージは起動後にsyslogに記録され、/var/log/messagesで参照できます。Saruは、saru.confまたはコマンドラインで直接debugオプションを指定することで、より詳しいログを行うことができます。デバッグを行う場合は、saruがログをターミナルに表示するようにした上でこのオプションを指定することをお勧めします。
saru --debug --log_facility -
デフォルトでは、起動後、saruはクラスタに加わる前に30秒間待機します。これにより、Linux Directorが起動した際に接続の同期化を行う時間が確保できます。これはランタイムに、saru.confまたはコマンドラインで直接設定することができます。
インターフェイスのMACアドレスとIPアドレスは、ipコマンドを使って設定できます。
ip link set eth0 down ip link set eth0 address 00:50:56:14:03:40 ip link set eth0 up ip route add default via 172.16.0.254 ip addr add dev eth0 192.168.20.40/24 broadcast 255.255.255.0
iptablesコマンドを使って、Saruが受け入れないVIP宛てのトラフィックをすべてフィルタアウトする規則が追加されています。これらの規則は、接続の同期化が行われることを前提にしているため、そうでない場合には、netfilterの接続トラッキング機能を使って、特定の接続が同じLinux Directorで処理されるようにするべきです。
iptables -F iptables -A INPUT -d 172.17.60.201 -p tcp -m saru --id 1 -j ACCEPT iptables -A INPUT -d 172.17.60.201 -p udp -m saru --id 1 -j ACCEPT iptables -A INPUT -d 172.17.60.201 -p icmp -m icmp --icmp-type echo-request \ -m saru --id 1 --sense src-addr -j ACCEPT iptables -A INPUT -d 172.17.60.201 -p icmp -m icmp --icmp-type ! echo-request \ -j ACCEPT iptables -A INPUT -d 172.17.60.201 -j DROP
LVS-NATが使われている場合は、すべてのLinux Directorが実サーバに代わって応答を送ることのないように、次の規則も必要になります。
iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -d 192.168.6.0/24 -j ACCEPT iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -m state --state INVALID \ -j DROP iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -m state --state ESTABLISHED \ -j ACCEPT iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -m state --state RELATED \ -j ACCEPT iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -p tcp -m state --state NEW \ --tcp-flags SYN,ACK,FIN,RST SYN -m saru --id 1 -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -p udp -m state --state NEW \ -m saru --id 1 -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -p icmp \ -m icmp --icmp-type echo-request -m state --state NEW \ -m saru --id 1 --sense dst-addr -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -p icmp \ -m icmp --icmp-type ! echo-request -m state --state NEW \ -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -j DROP
それぞれの接続へのパケットをどのLinux Directorが受け取るかは、ipvsadm -L INPUT -n -vを使って監視できます。次の出力は、Linux Director Aによって負荷分散が行われた接続を示しています。
ipvsadm -L INPUT -n -v # Linux Director A Chain INPUT (policy ACCEPT 92541 packets, 14M bytes) pkts bytes target prot opt in out source destination 5 1551 ACCEPT tcp -- * * 0.0.0.0/0 172.17.60.201 saru id 1 sense src-port 0 0 ACCEPT udp -- * * 0.0.0.0/0 172.17.60.201 saru id 1 sense src-port 0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.17.60.201 icmp type 8 saru id 1 sense src-addr 0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.17.60.201 icmp !type 8 0 0 DROP all -- * * 0.0.0.0/0 172.17.60.201
ipvsadm -L INPUT -n -v # Linux Director B Chain INPUT (policy ACCEPT 92700 packets, 15M bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.17.60.201 saru id 1 sense src-port 0 0 ACCEPT udp -- * * 0.0.0.0/0 172.17.60.201 saru id 1 sense src-port 0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.17.60.201 icmp type 8 saru id 1 sense src-addr 0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.17.60.201 icmp !type 8 5 1551 DROP all -- * * 0.0.0.0/0 172.17.60.201
LVSは、インターネット・サービスのクラスタ化を実装する効率的な方法です。heartbeat、ldirectord、keepalivedなどのツールを使うことで、クラスタを高可用性にすることができます。LVSクラスタをさらに拡張するために利用できるテクニックは他にも多数あります。アクティブ・フィードバックを使えばそれぞれの実サーバに割り振られる接続の割合を決定できます。また、接続の同期化とActive/Activeは、複数のLinux Directorがよりよく協力し合うのに役立ちます。
LVS自体は非常に強力なツールであり、本稿では扱うことのできなかった数々の機能が用意されています。たとえば、仮想サービスをグループ化するためのファイアウォール・マーク、特殊なスケジューリング・アルゴリズム、さまざまなチューニング用パラメータなどです。そのほか、ユーザのニーズに対応し、ますます複雑化するインターネットを反映できるよう、LVSの機能を拡張することについては、さらなる議論が可能です。
keepalived(マスタ)のサンプル設定ファイル
global_defs { notification_email { admin@some.domain } notification_email_from admin@some.domain smtp_server 210.128.90.2 smtp_connect_timeout 30 lvs_id LVS_DEVEL } vrrp_sync_group VG1 { group { VI_1 VI_2 } } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.17.60.201 } } vrrp_instance VI_2 { state MASTER interface eth1 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.6.1 } } virtual_server 172.17.60.201 80 { delay_loop 6 lb_algo lc lb_kind NAT nat_mask 255.255.255.0 !persistence_timeout 50 protocol TCP real_server 192.168.6.4 80 { weight 1 HTTP_GET { url { path / digest 55fd843c4e99e96c1ef28e7dbb10c51b } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.6.5 80 { weight 1 HTTP_GET { url { path / digest 90bfbce6bc089a41f1fddca9aeaba452 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } sorry_server 127.0.0.1 80 }
keepalived(スレーブ)のサンプル設定ファイル
global_defs { notification_email { admin@some.domain } notification_email_from admin@some.domain smtp_server 210.128.90.2 smtp_connect_timeout 30 lvs_id LVS_DEVEL } vrrp_sync_group VG1 { group { VI_1 VI_2 } } vrrp_instance VI_1 { state SLAVE interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.17.60.201 } } vrrp_instance VI_2 { state SLAVE interface eth1 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.6.1 } } virtual_server 172.17.60.201 80 { delay_loop 6 lb_algo lc lb_kind NAT nat_mask 255.255.255.0 !persistence_timeout 50 protocol TCP real_server 192.168.6.4 80 { weight 1 HTTP_GET { url { path / digest 55fd843c4e99e96c1ef28e7dbb10c51b } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.6.5 80 { weight 1 HTTP_GET { url { path / digest 90bfbce6bc089a41f1fddca9aeaba452 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } sorry_server 127.0.0.1 80 }