IPVSに対して今後の導入が考えられるいくつかの拡張について簡単に紹介します。

MACアドレスの持続性エンジン

ステートフルファイアウォールの背後でトラフィックの負荷分散を行うときには、受信パケットをフィルタリングしたのと同じファイアウォールに返信パケットを送信することが重要な場合があります。

 

「Load Balancing 101:Firewall Sandwiches」 (負荷分散101:ファイアウォールサンド) には、このような環境での負荷分散について、次のような記述があります。

多くのADCベンダーは、「ラストホップ」や「リバースパーシステンス」と呼ばれる機能をサポートしています。
この機能を使うと、ADC #2は、元のリクエストを送信したデバイスのMACアドレスを表す接続状態エントリを別に作成します。
ADC #2は、従来の意味で言うルーティングを行うのではなく、受信元のファイアウォールのMACアドレスにトラフィックを転送するのみです。

この文書が言うADC(Application Delivery Controllers)とはディレクターのことです。
筆者としては、上で述べられている機能は、IPVSにMAC持続性エンジンを搭載すれば実現できると考えます。そうすれば、IPVSでリクエストをスケジューリングするときに、IPアドレスとポートだけでなく (あるいはその代わりとして)、MACアドレスに基づいて行えるようになります。

GREトンネルと負荷分散

Generic Routing Encapsulation (GRE) は、さまざまなネットワークプロトコルをIPパケットの中にカプセルできるステートレスプロトコルです。
2つのエンドポイント間でトンネルを作成するために使います。一般に、トンネルのエンドポイントのIPアドレスを外側のアドレスと呼び、カプセル化した内部パケットのアドレスを内側のアドレスと呼びます。

GREパケットのプロトコル番号は47です。GREパケットでは、IPヘッダーの後にGREパケットヘッダーが付いています。GREパケットヘッダーには、同じエンドポイント間の2つのGREトンネルを区別するためのキーが含まれています。

IPVSにGRE向けのトランスポートプロトコルレベルのサポートを追加すれば、GREの負荷分散を実現できるはずです。実サーバへの接続をスケジューリングするためのキーの候補としては、外側のIPアドレスに加えて、GREキーや、内側のIPアドレスおよびポートの使用が考えられます。

同期

IPVSの同期デーモンは、マルチキャストグループ224.0.0.81のポート8848を利用しています。次のようにすれば、柔軟性が高まるはずです。

  • マルチキャストグループとポートを設定できるようにする。
  • IPv6グループを利用できるようにする。
  • 複数のグループとポートを使えるようにする。

さらに、正式なシステムとして確立し、競合の可能性を防ぐために、ポート番号をInternet Assigned Numbers Authority(IANA)に登録し、その番号を使うようにするのがよいと思います。

LROの再分割

トラブルシューティングの「LROとGRO」のセクションで説明したように、Large Receive Offload (LRO) とは、ハードウェアアクセラレーションを利用して同じ接続に対する複数のパケットを1つの大きなパケットに結合し、それを Linuxカーネルのネットワークスタックで処理するという手法です。

こうして生成したパケットは、IPVS が転送に使用するインターフェイスの MTU よりも大きいのが一般的です。このようなパケットを再分割する機能を IPVS に追加すれば、IPVS を LRO と組み合わせて利用できるようになり、LRO がパフォーマンスにもたらすメリットをディレクターで生かすことができます。

スロースタート (Thundering Herd)

接続のスケジューリングアルゴリズムとしてwlcを使用しており、既に負荷が高い状態にあるクラスタに対して、新しい実サーバを追加すると、それからしばらくの間は、新しい接続はすべてその実サーバに割り当てられます。

その実サーバが扱う接続の数が、クラスタ内の他の実サーバと同程度になるまでは、その状況が続きます。新しい接続への対応にかかるコストが、既存の接続への対応にかかるコストに比べてかなり大きい状況では、新たに追加した実サーバが過負荷になる可能性があります。 こうした問題は Thundering Herd 問題と呼ばれることもあります。

筆者は、この問題を緩和するための策として、新しい実サーバには負荷を高くみなす人為的なハンディキャップを与え、時間の経過とともに徐々に減らしていくという方法を提案しています。
このような人為的なハンディキャップを与えれば、新しい実サーバの接続数がクラスタ内の他の実サーバと同程度のレベルに達するまでの間は、その実サーバに新しい接続がスケジューリングされるペースが下がるという発想です。

この方法はもともと、2004年にメーリングリストへの投稿で提案したもので、この文書の執筆時点では、カーネル3.2へのポーティングが進んでいます。

ICMPリダイレクトによるゲートウェイの変更の問題

LVSクラスタでは、実サーバはファーストホップゲートウェイとしてDIPを使うのが一般的です。 さらに、DIPがフローティングIPアドレスの場合には、ディレクターが実サーバとの通信に使用するネットワークインターフェイスプライマリ IP アドレスとは異なるのが普通です。

ディレクターが、実サーバに別のゲートウェイを使用させるなどの目的でICMPリダイレクトを送信するときには、その送信元IPアドレスは、伝送に使うネットワークインターフェイスのプライマリ IP アドレスとなります。しかし、RFC1122 (インターネットホストの要件 ? 通信レイヤ: http://tools.ietf.org/html/rfc1122) の3.2.2.2項の2番目の条件によると、このようなリダイレクトは破棄する必要があります。

リダイレクトメッセージで指定された新しいゲートウェイアドレスが、リダイレクトが届いたのと同じ接続先 (サブ) ネット上にない場合 [INTRO:2, Appendix A]、またはリダイレクトの送信元が指定された宛先に対する現在のファーストホップゲートウェイと異なる場合 (IPVS=NAT項を参照) には、リダイレクトメッセージを暗黙的に破棄する必要がある。

筆者は、この問題に関する netdev メーリングリスト での議論において、実サーバのカーネルでこの条件を緩和できるようにするための設定パラメーターを提案しました。

しかし、この提案が受け入れられるかどうかははっきりしません。また、受け入れられるとしても、Linuxの実サーバ以外ではこの問題に対処できません。

防御戦略ごとのしきい値

IPVSには、DoS攻撃、エントリのドロップ、パケットのドロップ、セキュアTCPに伴う影響を抑えるための防御戦略がいくつか用意されています。
それぞれの防御戦略は、procエントリのam_thresholdに基づいて、カーネルが使用可能な空きメモリに応じて自動で有効化および無効化できます。
しかし、3つの防御戦略すべてがこのprocエントリを共通で使用するため、防御戦略を自動で連鎖的に適用するようにカーネルを設定することはできません。

たとえば、ある閾値に達したらエントリのドロップの戦略を自動で適用し、それより低い閾値では、パケットのドロップの戦略を適用する、という運用が望ましい場合もあります。防御戦略ごとに個別のprocエントリがあれば、そのような処理もカーネルで実現できます。

同様に、procエントリのam_droprateは、drop_entryの防御戦略でエントリをドロップするレートと、drop_packetの防御戦略でパケットをドロップするレートを共通で表します。procエントリが異なっていれば、それぞれのドロップレートを個別に設定できることになります。