SLB ist ein sitzungsloser Load Balancer für UDP-Datenverkehr und löst Probleme, die mit der Verwendung herkömmlicher (funktionsreicher) Load Balancer für solchen Datenverkehr verbunden sind.
Für einfache, zustandslose UDP-Protokolle bietet es keinen Vorteil, die „Affinität“ (auch bekannt als „Sitzungen“) zwischen Clients und Back-End-Instanzen aufrechtzuerhalten. Herkömmliche Load Balancer gehen davon aus, dass Affinität hilfreich ist, und versuchen daher, Pakete von einem Client an einen konsistenten Back-End-Server weiterzuleiten. Im Gegensatz dazu verteilt SLB die Pakete gleichmäßig (zufällig) einzeln über alle verfügbaren Back-Ends. Dies führt zu einer gleichmäßigen Belastung der Backends und einer verbesserten Robustheit, wenn eine Backend-Instanz ausfällt (es kommt zu einem Anstieg des Paketverlusts für alle Clients und nicht zu einem vollständigen Datenverkehrsverlust für einige Clients).
Standardmäßig überwacht SLB die Ports 1812
und 1813
auf eingehende UDP-Pakete und leitet sie an zufällige, ihm bekannte Backend-Ziele weiter. Die Ports, auf denen es lauscht, können mit der Option --server-port-range
ausgewählt werden, die einen einzelnen Port (z. B. 541
) oder einen Bereich von Ports (z. B. 4000-5000
) akzeptiert.
Um SLB auf Backends aufmerksam zu machen, müssen „Watchdog“-Pakete (auch bekannt als „Keep Alive“) an den Admin-Port gesendet werden (mehr dazu weiter unten). Standardmäßig ist der Admin-Port 1111
, er kann jedoch mit der Option --admin-port
konfiguriert werden. Wenn in Ihrem System mehrere Netzwerkkarten vorhanden sind, können Sie die IP mit der Option --admin-ip
angeben. Wenn die mit --admin-ip
angegebene IP im Multicast-CIDR-Bereich ( 244.0.0.0/4
) liegt, tritt SLB automatisch dieser Multicast-Gruppe bei (mehr dazu weiter unten).
Weitere Optionen sind in der Befehlshilfe beschrieben:
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
Backends werden nicht über die Befehlszeile konfiguriert. Vielmehr werden sie mithilfe regelmäßiger UDP-Pakete, die an den Admin-Port ( --admin-port
) gesendet werden, dynamisch registriert und deregistriert. Der Inhalt dieser Pakete kann je nachdem, wie Sie SLB in Ihrer Umgebung verwenden, unterschiedlich sein.
Wenn Sie einen einzelnen SLB-Server betreiben, können Backends so konfiguriert werden, dass sie Pakete an diese eine IP und an den Admin-Port senden. Dies ist das einfachste Szenario. Jedes Backend sendet Nachrichten mit zwei „magischen Bytes“, um die „Backend-Registrierung“ für Inhalte anzuzeigen:
0x11 0x11
SLB interpretiert ein solches Paket als „den Absender als Backend registrieren“. Optional können die Nachrichten ein oder zwei zusätzliche Bytes (Gewicht und Gruppen-ID) enthalten, auf deren Zweck weiter unten näher eingegangen wird.
0x11 0x11 [X] [X]
^ ^
| |
| one byte for group id
|
one byte for weight
In einigen Umgebungen werden Registrierungspakete nicht von den Backends selbst gesendet, und SLB unterstützt solche Anwendungsfälle. Wenn ein Registrierungspaket von einem „Dritten“ gesendet wird, muss der Inhalt die IP-Adresse des zu registrierenden Backends enthalten:
0x11 0x11 X X X X [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
Auch hier können optional die Gewichts- und Gruppen-ID-Bytes angehängt werden.
Wenn eine robustere HA-Bereitstellung mit mehreren SLBs erforderlich ist, kann die Kommunikation zwischen Backends und SLB durch die Verwendung einer Multicast-Gruppen-IP vereinfacht werden. Dies ist hilfreich, da jeder SLB jedes Backend kennen muss. In einem solchen Fall sollten die SLB-Server die Option --admin-ip
verwenden, um eine Multicast-Adresse anzugeben, die dazu führt, dass die SLBs der Multicast-Gruppe beitreten und somit alle alle an diese IP gesendeten Nachrichten empfangen. Die Backends können mit dieser einzigen IP konfiguriert werden, was ihren Arbeitsaufwand minimiert und ihre Konfiguration vereinfacht (insbesondere, wenn SLBs aufgrund von Autoscaling und/oder der Verwendung von Spot-Instanzen rotierend in und außer Betrieb genommen werden).
Beachten Sie, dass die Verwendung einer Multicast-IP entweder einen Switch erfordert, der Multicast unterstützt, oder (wahrscheinlicher) die Ausführung in einer AWS VPC, die mit einer Multicast-Domäne konfiguriert ist.
Die Admin-Paketformate sind ab Version 2.0 sehr einfach. Im einfachsten Einzel-SLB-Anwendungsfall darf ein Registrierungspaket von einem Backend aus nicht mehr als zwei magischen Bytes ( 0x11
0x11
) bestehen. Optional können die Pakete von einer anderen Quelle (z. B. einem Management-Server) stammen und vier Bytes zur Angabe der IPv4-Adresse eines Backends enthalten. In beiden Fällen können zwei zusätzliche optionale Bytes für das „Gewicht“ des Datenverkehrs im Verhältnis zu anderen Backends und für die Zuweisung der „Gruppe“ zum Backend angehängt werden (mehr zu Gruppen weiter unten). In ASCII-Grafik:
0x11 0x11 [X X X X] [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
Um ein Ziel sofort zu entfernen, senden Sie ein Paket mit 0x86
als erstem Byte anstelle von 0x11
(wenn es von einem Verwaltungsserver gesendet wird, hängen Sie die IP des zu entfernenden Backends an):
0x86 0x11 [X X X X]
^
|
four bytes for ip to remove
Gewichtungen werden verwendet, um die relative Menge des an jedes Backend gelieferten Datenverkehrs zu steuern. Wenn keine Gewichtung angegeben ist, wird der Standardwert 100 (konfigurierbar mit --default-target-weight
) auf das Backend angewendet und jedes erhält das gleiche Paketvolumen. Allerdings wird erwartet (und empfohlen), dass Back-Ends den Gewichtungswert in ihren Admin-Paketen basierend auf ihrer Fähigkeit, Datenverkehr zu verarbeiten, anpassen (möglicherweise reduziert, wenn die CPU hoch ist, Updates angewendet werden usw.). Zum Beispiel:
100
, 50
bzw. 50
bekannt sind, erhält das erste 50 % des Datenverkehrs und das zweite und dritte jeweils 25 %.31
bzw. 31
bekannt sind, erhält jedes 50 % des Datenverkehrs.Bei der Verwendung von Gruppen werden die relativen Gewichtungen im Vergleich zu anderen Backends in derselben Gruppe ausgewertet (nicht über alle Gruppen hinweg).
Es ist wichtig, Admin-Pakete zuverlässig und in ausreichender Häufigkeit zu versenden. Jedes Mal, wenn ein Paket vom SLB empfangen wird, wird die „Zuletzt gesehen“-Zeit des Backends aktualisiert. Wenn 30 Sekunden (konfigurierbar mit
--target-timeout
) vergehen, ohne dass ein Backend gesehen wird, wird es entfernt und es wird kein weiterer Datenverkehr an es gesendet.
Standardmäßig werden alle Backends verwendet, um alle vom Load Balancer bedienten Ports zu bedienen.
Es ist jedoch möglich, einzelne Ports Teilmengen von Backends zuzuweisen, indem Sie SLB-Portzuweisungsnachrichten verwenden und Gruppen-IDs in Registrierungsnachrichten angeben. Stellen Sie sich beispielsweise vor, dass Sie einen SLB-Lastenausgleich für den Datenverkehr für die Ports 1812–1813 wünschen, aber den Datenverkehr, der jeden Port erreicht, einer anderen Gruppe von Servern zuweisen möchten. Gehen Sie dazu wie folgt vor:
x66 x11
) mit einer Portnummer (zwei Bytes) und einer Gruppen-ID (ein Byte). Diese Nachrichten müssen nicht wiederholt werden und können gesendet werden, wenn eine Änderung der Portgruppenzuweisungen gewünscht wird (es schadet jedoch nicht, sie zu wiederholen, was praktisch sein kann, um sicherzustellen, dass den Ports nach dem Neustart des Dienstes korrekte Gruppen zugewiesen werden). 0x66 0x11 X X X
^ ^
| |
| one byte for group ID
|
two bytes for port number, litten endian
Mit Linux bash
ist das Versenden von Admin-Paketen unkompliziert. Dies kann mit dem Befehl netcat
(auch bekannt als nc
) oder dem Dateisystem /dev/udp
erfolgen. Wenn Ihr Load Balancer beispielsweise den Standard-Administrator-Port 1111
überwacht und Sie ein Ziel mit der IP 192.168.1.22
hinzufügen möchten:
$ echo -e $( echo " x11x11 $( echo " 192.168.1.22 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.0.0.1/1111
Da es mühsam sein kann, diese Pakete manuell zu senden, um eine Reihe von Zielen registriert zu halten, können Sie ein kleines Shell-Skript erstellen, beispielsweise 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
Und dann verwenden Sie den Befehl watch
, um dieses Skript alle paar Sekunden aufzurufen:
$ watch -n10 ./lb.sh
Vorgefertigte Binärdateien für Linux und Windows x64 sowie Linux ARM sind als GitHub „Releases“ verfügbar. Dies ist ein sehr einfaches .Net 8.0-Projekt. Um es zu erstellen, führen Sie Folgendes aus (vorausgesetzt, Sie haben dotnet-sdk-8.0 installiert):
dotnet build
Sie möchten wahrscheinlich eine native binäre ausführbare Datei generieren, was praktisch ist und einige Leistungsvorteile bietet.
Für Linux:
dotnet publish -o ./ -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
Für Windows:
dotnet publish -o ./ -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
Ebenso einfach ist die Ausführung mit dotnet run
im Projektverzeichnis:
$ dotnet run
Oder, wenn Sie eine native ausführbare Datei erstellt haben:
$ ./SimplestLoadBalancer
Für Fragen und Fehlerberichte können Sie gerne hier auf GitHub Issues erstellen. Es gibt keine Vorlage oder Anforderungen, aber versuchen Sie bitte, so beschreibend wie möglich zu sein – so stellen wir sicher, dass wir in der Lage sind, vernünftig zu reagieren. Siehe auch, beitragen.
Genießen!