web-dev-qa-db-ja.com

UDPのパケットごとのラウンドロビン負荷分散

多数の「実サーバー」間でUDPトラフィックの負荷を分散し、真のラウンドロビン方式で実行する必要があります。私はkeepalivedから始めましたが、予期せぬことに、LVSがUDPトラフィックを「接続」として扱うことを発見しました(UDPに関しては何でも)。実際には、これは、特定のクライアントからのすべてのトラフィックが常にまったく同じ「実サーバー」に送信されることを意味します(一部のクライアントは大量のトラフィックを生成する可能性があるため、単一のバックエンドが圧倒されるため、これは大きな問題です) 。

どうやら、これは予想される動作です。ただし最近のLVSバージョンには「--ops」フラグがあり、LVSが前述の動作をバイパスして、各UDPデータグラムが個別に処理されるようにします(これが私が望むものです! )。しかし(常にありますが..)この機能はkeepalived.confから公開されていません。

そこに解決策はありますか、それは私を可能にします

  • uDPのバックエンド間でラウンドロビン配布を行う
  • 「デッド」バックエンドを検出し、ラウンドロビンから削除します(「アライブ」になったときにバックエンドを追加することも役立ちます)

明らかに、Linuxベースである必要があります。クライアントはDNSに対応していないため、どのような形式のDNSラウンドロビンもここでは実際には機能しません。

P.S. Pulse/piranhaを試してみますが、収集したドキュメントを読んだところ、「-ops」フラグも公開されていないことがわかりました。また、monを試してみます(monを確認し、ipvsadmを直接呼び出して実サーバーを追加/削除します)。

4
shylent

要件は次のように満たされました。

--opsフラグ(1.26)をサポートする最新バージョンのipvsadm(およびそのカーネルモジュール)をインストールしました。 keepalivedはこのフラグを構成ファイルに公開しないため、手動で適用する必要があります。幸いなことに、それを行うことができます「仮想サービス」が作成されます(プレーンipvsadmに関しては、最初にipvsam -Aなしで仮想サービスを--opsし、次にipvsadm -E 1つのパケットスケジューリングを追加します)。

Keepalivedは仮想サービスを作成するため、作成後に編集するだけで済みます。これは、この仮想サーバーのクォーラムが取得されたときに発生します(基本的に、十分な数の稼働中の実サーバーがあります)。 keepalived.confファイルでの表示は次のとおりです。

virtual_server <VIP> <VPORT> {
    lb_algo rr
    lb_kind NAT
    protocol UDP
    ...

    # Enable one-packet scheduling when quorum is gained
    quorum_up "ipvsadm -E -u <VIP>:<VPORT> --ops -s rr"

    ... realserver definitions, etc ...
}

これは機能しますが、この設定でいくつかの問題(種類)が発生しました:

  1. クォーラムが上昇してからquorum_upのスクリプトが実行されるまでには、わずかな時間差(1秒未満、1/10など)があります。その間にダイレクタを通過することに成功したデータグラムは、ipvsadmに接続エントリを作成し、そのソースホスト/ポートからのデータグラムは同じ実サーバーにスタックします--opsフラグが追加。仮想サービスが作成された後は決して削除されないようにすることで、これが発生する可能性を最小限に抑えることができます。これを行うには、実サーバー定義でinhibit_on_failureフラグを指定して、対応する実サーバーがダウンしたときに削除されないようにします(すべての実サーバーが削除されると、仮想サービスも削除されます)が、代わりに重みがゼロに設定されます(その後、トラフィックの受信を停止します)。その結果、データグラムがスリップする可能性があるのは、keepalivedの起動時のみです(その時点で少なくとも1つの実サーバーが稼働していると仮定すると、クォーラムはすぐに取得されます)。
  2. --opsがアクティブな場合、ダイレクタは実サーバーがクライアントに送信するデータグラムのソースホスト/ポートを書き換えないため、ソースホスト/ポートはこの特定のデータグラムを送信した実サーバーのものです。これは問題になる可能性があります(myクライアントの場合でした)。これらのデータグラムをiptablesでSNAT 'することで、これを修正できます。
  3. ダイレクタに負荷がかかっているときのCPU負荷が大きいことに気づきましたsystem。結局のところ、CPUはksoftirqdによって占有されています。 --opsをオフにしても発生しません。おそらく、問題は、「接続」の最初のデータグラムだけでなく、すべてのデータグラムでパケットディスパッチングアルゴリズムが実行されることです(UDPにも当てはまる場合)。私は実際にそれを「修正」する方法を見つけていませんが、多分私は十分に努力していません。システムにはいくつかの特定の負荷要件があり、その負荷の下ではプロセッサの使用量が最大になりません。データグラムが失われることもないため、この問題は目立たないものとは見なされません。それでもまだかなり憂慮すべきです。

要約:セットアップは間違いなく機能しますが(負荷がかかっている場合でも)、フープを飛び越えなければならず、私が遭遇した問題(特に№3..誰かが解決策を知っていますか?)、つまり、時間があれば、私はUDPソケットでリッスンし、受信したデータグラムを実サーバー間で配布するために、ユーザースペースプログラム(おそらくCで記述)を使用しました。これは、実サーバーの状態をチェックするものと組み合わせて、iptablesでSNATを書き換えます。ソースホスト/ポートおよびHAのVRRPモードでのkeepalived。

5
shylent

マルチパスルーティングでこれを行う方法が必要です。

ロードバランサーと実サーバーはサブネット(10.0.0/24)でIPを共有します。両方の実サーバーについて、ループバックインターフェイス(172.16.1.1/32)のセカンダリとして、別のサブネットから同じIPを追加します。サービスがリッスンするのはこのアドレスです。

                              +-------------------------------------+
                         +----|A: eth0:10.0.0.2/24 lo:172.16.1.1/32 |
+--------------------+   |    +-------------------------------------+
|LB eth0:10.0.0.1/24 |---|
+--------------------+   |    +-------------------------------------+
                         +----|B: eth0:10.0.0.3/24 lo:172.16.1.1/32 |
                              +-------------------------------------+

そして、あなたは使用することができます:

 ip route add 172.16.1.1/32 nexthop via 10.0.0.2 nexthop via 10.0.0.3

しかし、これまでのところ朗報です。明らかに最近のLinuxカーネルはルートをキャッシュするため、同じ送信元からのパケットは同じ宛先に送信されます。この動作を無効にするパッチがいくつかありますが、それらはすべて古いカーネル用のようです(2.4カーネルのマルチパスイコライズパッチ、2.6のmpathなど)。もっと徹底的に検索すると、最近のカーネルの有効なパッチが見つかるかもしれません。

10.0.0.2と10.0.0.3の両方でCARPを実行することで、簡単に実現できるフェイルオーバー。そうすれば、AがダウンしたときにBが10.0.0.2を引き継ぎます。

1
Zabuzzman