SLB は、UDP トラフィック用のセッションレス ロード バランサであり、そのようなトラフィックに対する従来の (機能が豊富な) ロード バランサの使用に固有の問題を解決します。
シンプルでステートレスな UDP プロトコルの場合、クライアントとバックエンド インスタンス間の「アフィニティ」 (別名「セッション」) を維持しようとしても利点はありません。従来のロード バランサーは、アフィニティが役立つと想定しているため、クライアントから一貫したバックエンド サーバーにパケットをルーティングしようとします。対照的に、SLB は、利用可能なすべてのバックエンドにパケットを 1 つずつ均等に (ランダムに) 分散します。これにより、バックエンドの負荷が均一になり、1 つのバックエンド インスタンスに障害が発生した場合の堅牢性が向上します (一部のクライアントのトラフィック全体の損失ではなく、すべてのクライアントのパケット損失が増加します)。
デフォルトでは、SLB はポート1812
および1813
で受信 UDP パケットをリッスンし、認識しているランダムなバックエンド ターゲットにパケットを中継します。リッスンするポートは--server-port-range
オプションで指定でき、単一のポート (例: 541
) またはポート範囲 (例: 4000-5000
) を受け入れます。
SLB にバックエンドを認識させるには、「ウォッチドッグ」(別名「キープアライブ」) パケットを管理ポートに送信する必要があります (これについては以下で詳しく説明します)。デフォルトでは、管理ポートは1111
ですが、 --admin-port
オプションを使用して構成できます。システムに複数のネットワーク カードが存在する場合は、 --admin-ip
オプションを使用して IP を指定できます。 --admin-ip
で指定された IP がマルチキャスト CIDR 範囲 ( 244.0.0.0/4
) 内にある場合、SLB は自動的にそのマルチキャスト グループに参加します (詳細は下記を参照)。
他のオプションについては、コマンドのヘルプで説明されています。
SimplestLoadBalancer:
Sessionless UDP Load Balancer sends packets to backends without session affinity.
Usage:
SimplestLoadBalancer [options]
Options:
--server-port-range <server-port-range> Set the ports to listen to and forward to backend targets
(default "1812-1813") [default: 1812-1813]
--admin-ip <admin-ip> Set the IP to listen on for watchdog events [default is first private IP]
--admin-port <admin-port> Set the port that targets will send watchdog events [default: 1111]
--client-timeout <client-timeout> Seconds to allow before cleaning-up idle clients [default: 30]
--target-timeout <target-timeout> Seconds to allow before removing target missing watchdog events [default: 30]
--default-target-weight <default-target-weight> Weight to apply to targets when not specified [default: 100]
--unwise Allows public IP addresses for targets [default: False]
--stats-period-ms <stats-period-ms> Sets the number of milliseconds between statistics messages printed to the
console (disable: 0, max: 65535) [default: 1000]
--default-group-id <default-group-id> Sets the group ID to assign to backends that when a registration packet doesn't
include one, and when port isn't assigned a group [default: 0]
--version Show version information
-?, -h, --help Show help and usage information
バックエンドはコマンド ラインでは構成されません。むしろ、管理ポート ( --admin-port
) に送信される定期的な UDP パケットを使用して、動的に登録および登録解除されます。これらのパケットの内容は、環境での SLB の使用方法によって異なる場合があります。
単一の SLB サーバーを実行している場合は、その 1 つの IP と管理ポートにパケットを送信するようにバックエンドを構成できます。これは最も単純なシナリオです。各バックエンドは、コンテンツの「バックエンド登録」を示す 2 つの「マジック バイト」を含むメッセージを送信します。
0x11 0x11
SLB は、そのようなパケットを「送信者をバックエンドとして登録する」ものとして解釈します。オプションで、メッセージには 1 つまたは 2 つの追加バイト (重みとグループ ID) を含めることができます。その目的については、以下で詳しく説明します。
0x11 0x11 [X] [X]
^ ^
| |
| one byte for group id
|
one byte for weight
一部の環境では登録パケットがバックエンド自体から送信されず、SLB はそのような使用例をサポートします。登録パケットが「サードパーティ」から送信される場合、コンテンツには登録されるバックエンドの IP アドレスが含まれる必要があります。
0x11 0x11 X X X X [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
再度、重みとグループ ID バイトをオプションで追加することもできます。
複数の SLB を備えたより堅牢な HA 導入が必要な場合、マルチキャスト グループ IP を使用することでバックエンドと SLB 間の通信を簡素化できます。各 SLB は各バックエンドを認識する必要があるため、これは役立ちます。このような場合、SLB サーバーは--admin-ip
オプションを使用してマルチキャスト アドレスを指定する必要があります。これにより、SLB がマルチキャスト グループに参加し、すべての SLB がその IP に送信されたメッセージを受信できるようになります。バックエンドはその 1 つの IP で構成できるため、ワークロードが最小限に抑えられ、構成が簡素化されます (特に、自動スケーリングやスポット インスタンスの使用により SLB がサービスのインとアウトをローテーションする場合)。
マルチキャスト IP を使用するには、マルチキャストをサポートするスイッチ、または (おそらく) マルチキャスト ドメインで構成された AWS VPC で実行されているスイッチが必要であることに注意してください。
バージョン 2.0 では、管理パケットの形式は非常にシンプルです。最も単純な単一 SLB の使用例では、バックエンドからの登録パケットは 2 つのマジック バイト ( 0x11
0x11
) のみで構成されます。オプションで、パケットは別のソース (管理サーバーなど) から送信され、バックエンドの ipv4 アドレスを指定する 4 バイトを含めることができます。いずれの場合も、他のバックエンドに対するトラフィックの「重み」と、バックエンドに割り当てる「グループ」用のオプションの 2 バイトを追加できます (グループについては以下で詳しく説明します)。アスキーアートでは:
0x11 0x11 [X X X X] [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
ターゲットをすぐに削除するには、最初のバイトが0x11
ではなく0x86
のパケットを送信します (管理サーバーから送信された場合は、削除するバックエンドの IP を追加します)。
0x86 0x11 [X X X X]
^
|
four bytes for ip to remove
重みは、各バックエンドに配信されるトラフィックの相対量を制御するために使用されます。重みが指定されていない場合、デフォルト値の 100 ( --default-target-weight
で構成可能) がバックエンドに適用され、それぞれが同じ量のパケットを受信します。そうは言っても、バックエンドがトラフィックを処理する能力に基づいて管理パケットの重み値を調整することが期待されています (また、推奨されています) (CPU 使用率が高い場合、更新が適用されている場合などは、おそらく減少します)。例えば:
100
、 50
、および50
の重みを持つ SLB に認識されている場合、最初のバックエンドはトラフィックの 50% を受け取り、2 番目と 3 番目はそれぞれ 25% を受け取ります。31
および31
で SLB に認識されている場合、それぞれがトラフィックの 50% を受信します。グループを使用する場合、同じグループ内の他のバックエンドと比較して相対的な重みが評価されます (すべてのグループにわたるわけではありません)。
管理パケットを十分な頻度で確実に送信することが重要です。 SLB がパケットを受信するたびに、バックエンドの「最後に確認された」時刻が更新されます。バックエンドが表示されないまま 30 秒 (
--target-timeout
で構成可能) が経過すると、そのバックエンドは削除され、それ以上のトラフィックは送信されなくなります。
デフォルトでは、ロード バランサーが提供するすべてのポートにサービスを提供するために、すべてのバックエンドが使用されます。
ただし、SLB ポート割り当てメッセージを使用し、登録メッセージでグループ ID を指定することにより、バックエンドのサブセットに個々のポートを割り当てることができます。たとえば、ポート 1812 ~ 1813 のトラフィックを SLB 負荷分散し、各ポートに到達するトラフィックを別のサーバーのセットに割り当てるとします。そのためには:
x66 x11
) を送信します。これらのメッセージは繰り返す必要はなく、ポート グループの割り当てを変更したいときに送信できます (ただし、メッセージを繰り返しても問題はありません。サービスの再起動後にポートにグループが正しく割り当てられるようにするのに便利です)。 0x66 0x11 X X X
^ ^
| |
| one byte for group ID
|
two bytes for port number, litten endian
Linux bash
使用すると、管理パケットを簡単に送信できます。これは、 netcat
(別名nc
) コマンドまたは/dev/udp
ファイルシステムを使用して実行できます。たとえば、ロード バランサーがデフォルトの管理ポート1111
でリッスンしており、IP 192.168.1.22
のターゲットを追加する場合は、次のようにします。
$ echo -e $( echo " x11x11 $( echo " 192.168.1.22 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.0.0.1/1111
一連のターゲットを登録したままにするためにこれらのパケットを手動で送信するのは面倒な場合があるため、小さなシェル スクリプト (たとえばlb.sh
) を作成するとよいでしょう。
#! /bin/bash
echo -ne $( echo " x11x11 $( echo " 192.168.1.22 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.23 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.24 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.25 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.26 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.27 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
次に、 watch
コマンドを使用して、数秒ごとにそのスクリプトを呼び出します。
$ watch -n10 ./lb.sh
Linux、Windows x64、および Linux ARM 用のビルド済みバイナリは、GitHub の「リリース」として入手できます。これは非常に単純な .Net 8.0 プロジェクトなので、ビルドするには次のコマンドを実行します (dotnet-sdk-8.0 がインストールされていると仮定します)。
dotnet build
おそらく、ネイティブ バイナリ実行可能ファイルを生成することをお勧めします。これは便利で、パフォーマンス上の利点も得られます。
Linuxの場合:
dotnet publish -o ./ -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
Windowsの場合:
dotnet publish -o ./ -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
同様に、プロジェクト ディレクトリでdotnet run
を使用して実行するのも簡単です。
$ dotnet run
または、ネイティブ実行可能ファイルをビルドした場合は、次のようにします。
$ ./SimplestLoadBalancer
質問やバグレポートについては、GitHub で自由に問題を作成してください。提供されるテンプレートや要件はありませんが、できる限り説明的なものにしてください。そうすることで、当社が賢明な方法で対応できるようになります。 「貢献」も参照してください。
楽しむ!