[ Herausgeber – Dieser Beitrag wurde ursprünglich im Jahr 2016 veröffentlicht und wurde aktualisiert, um die seitdem überarbeiteten NGINX-Funktionen zu verwenden. Weitere Einzelheiten finden Sie unter Erweiterte Protokollierung mit dem NGINX JavaScript-Modul und dem NGINX Plus-Dashboard . ]
Wir haben den TCP-Lastausgleich in NGINX Plus R5 eingeführt und in nachfolgenden Versionen kontinuierlich neue Funktionen sowie Unterstützung für den UDP-Lastausgleich hinzugefügt. In diesem Artikel untersuchen wir die wichtigsten Anforderungen für TCP-Lastausgleich und wie NGINX Plus diese erfüllt.
Um die Funktionen von NGINX Plus zu erkunden, verwenden wir eine einfache Testumgebung, die die Schlüsselkomponenten einer Anwendung mit einem skalierten Datenbank-Backend darstellt. Vollständige Anweisungen zum Erstellen der Testumgebung finden Sie im Anhang .
In dieser Umgebung fungiert NGINX Plus als Reverse-Proxy für den Datenbankserver und lauscht auf dem MySQL-Standardport 3306. Dies stellt eine einfache Schnittstelle zum Client bereit, während die MySQL-Backend-Knoten skaliert (und sogar offline genommen) werden können, ohne den Client in irgendeiner Weise zu beeinträchtigen. Als Client verwenden wir das Kommandozeilentool MySQL , welches die Frontend-Anwendung in der Testumgebung darstellt.
Viele der in diesem Artikel beschriebenen Funktionen gelten sowohl für NGINX Open Source als auch für NGINX Plus. Der Kürze halber beziehen wir uns durchgehend auf NGINX Plus und weisen ausdrücklich auf die Funktionen hin, die in NGINX Open Source nicht verfügbar sind.
Wir werden die folgenden Anwendungsfälle untersuchen:
Bevor Sie den Lastenausgleich für eine Anwendung konfigurieren, ist es wichtig zu verstehen, wie die Anwendung eine Verbindung zur Datenbank herstellt. Für die meisten unserer Tests verwenden wir das MySQL-Befehlszeilentool mysql(1)
, um eine Verbindung zum Galera-Cluster herzustellen, eine Abfrage auszuführen und dann die Verbindung zu schließen. Viele Anwendungsframeworks verwenden jedoch einen Verbindungspool , um die Latenz zu minimieren und die Datenbankserverressourcen effizient zu nutzen.
Der TCP-Lastausgleich wird im Stream-
Konfigurationskontext konfiguriert. Daher erstellen wir unsere grundlegende MySQL-Lastausgleichskonfiguration, indem wir der Hauptdatei nginx.conf einen Stream-
Block hinzufügen.
Dadurch wird unsere TCP-Lastausgleichskonfiguration von der Hauptkonfigurationsdatei getrennt. Anschließend erstellen wir stream.conf im selben Verzeichnis wie nginx.conf . Beachten Sie, dass das Verzeichnis conf.d standardmäßig für den HTTP
-Konfigurationskontext reserviert ist und das Hinzufügen von Stream
-Konfigurationsdateien zu diesem Verzeichnis daher nicht funktioniert.
Zuerst definieren wir eine Upstream-
Gruppe namens galera_cluster , die die drei MySQL-Knoten in unserem Galera-Cluster enthält. In unserer Testumgebung sind sie jeweils auf dem lokalen Host mit einer eindeutigen Portnummer erreichbar. Die Zonendirektive
definiert eine Speichermenge, die von allen NGINX Plus-Arbeitsprozessen gemeinsam genutzt wird, um den Lastausgleichszustand aufrechtzuerhalten. Der Server{}
-Block konfiguriert, wie NGINX Plus mit Clients umgeht. NGINX Plus lauscht auf dem MySQL-Standardport 3306 und leitet den gesamten Datenverkehr an den im Upstream-
Block definierten Galera-Cluster weiter.
Um zu testen, ob diese grundlegende Konfiguration funktioniert, können wir den MySQL-Client verwenden, um den Hostnamen des Knotens im Galera-Cluster zurückzugeben, mit dem wir verbunden sind.
$ echo "VARIABLEN ANZEIGEN, WO Variablenname = 'Hostname'" | mysql --protocol=tcp --user=nginx --password=plus -N 2> /dev/null Hostname node1
Um zu überprüfen, ob der Lastenausgleich funktioniert, können wir denselben Befehl wiederholen.
$ !!;!!;!! Hostname Knoten2 Hostname Knoten3 Hostname Knoten1
Dies zeigt, dass der standardmäßige Round-Robin-Lastausgleichsalgorithmus ordnungsgemäß funktioniert. Wenn unsere Anwendung jedoch einen Verbindungspool für den Zugriff auf die Datenbank verwendet (wie oben vorgeschlagen), führt das Öffnen von Verbindungen zum Cluster im Round-Robin-Verfahren wahrscheinlich zu einer unausgewogenen Anzahl von Verbindungen auf jedem Knoten. Darüber hinaus können wir eine Verbindung nicht mit einer bestimmten Arbeitslast gleichsetzen, da Verbindungen inaktiv sein können (auf eine Abfrage von der Anwendung warten) oder mit der Verarbeitung einer Abfrage beschäftigt sind. Ein besser geeigneter Lastausgleichsalgorithmus für langlebige TCP-Verbindungen ist Least Connections , konfiguriert mit der least_conn
-Direktive:
Wenn ein Client jetzt eine neue Verbindung zur Datenbank öffnet, wählt NGINX Plus den Clusterknoten mit der geringsten Anzahl aktueller Verbindungen aus.
Der große Vorteil der Verteilung der Datenbankarbeitslast auf einen Cluster besteht darin, dass dadurch auch eine hohe Verfügbarkeit gewährleistet wird. Mit der oben besprochenen Konfiguration markiert NGINX Plus einen Server als „ausgefallen“ und sendet keine TCP-Pakete mehr an ihn, wenn keine neue TCP-Verbindung hergestellt werden kann .
Zusätzlich zur Handhabung ausgefallener Server auf diese Weise kann NGINX Plus auch so konfiguriert werden, dass automatische, proaktive Integritätsprüfungen durchgeführt werden, sodass nicht verfügbare Server erkannt werden, bevor Clientanforderungen an sie gesendet werden (dies ist eine nur in NGINX Plus verfügbare Funktion). Darüber hinaus lässt sich die Verfügbarkeit von Servern mit einer Integritätsprüfung auf Anwendungsebene testen. Das heißt, wir können an jeden Server eine Anfrage senden und prüfen, ob wir eine Antwort erhalten, die auf eine gute Integrität hinweist. Dies erweitert unsere Konfiguration wie folgt.
In diesem Beispiel definiert der Match
-Block die Anforderungs- und Antwortdaten, die zum Initiieren eines Handshakes mit MySQL-Protokollversion 10 erforderlich sind. Die Direktive health_check
im Block server{}
wendet dieses Muster an und stellt sicher, dass NGINX Plus MySQL-Verbindungen nur an Server weiterleitet, die tatsächlich neue Verbindungen annehmen können. In diesem Fall führen wir die Integritätsprüfung alle 20 Sekunden durch, schließen einen Server nach einem einzelnen Fehler aus dem TCP-Lastausgleichspool aus und nehmen den Lastausgleich nach zwei aufeinanderfolgenden erfolgreichen Integritätsprüfungen wieder auf.
NGINX Plus bietet flexible Protokollierung, sodass die gesamte TCP/UDP-Verarbeitung zum Debuggen oder zur Offline-Analyse aufgezeichnet werden kann. Bei TCP-Protokollen wie MySQL schreibt NGINX Plus einen Protokolleintrag, wenn die Verbindung geschlossen wird. Die Direktive „log_format“
definiert, welche Werte in den Protokollen erscheinen. Wir können aus allen für die Stream-Module verfügbaren Variablen wählen. Wir definieren das Protokollformat im Streamkontext
oben in unserer Datei stream.conf .
Die Protokollierung wird aktiviert, indem im Block „server{}“
die Direktive „access_log“
hinzugefügt wird. Dabei wird der Pfad zur Protokolldatei und der Name des im vorherigen Snippet definierten Protokollformats angegeben.
Dadurch werden Protokolleinträge wie im folgenden Beispiel erstellt.
$ tail -3 /var/log/nginx/galera_access.log 192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 1611 127.0.0.1:33063 0.000 0.003 12.614 12.614 192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 8337 127.0.0.1:33061 0.001 0.001 11.181 11.181 192.168.91.1 [23/Jul/2021:17:42:19 +0100] TCP 200 369 1611 127.0.0.1:33062 0,001 0,001 10,460 10,460
NGINX JavaScript ist die „native“ programmierbare Konfigurationssprache von NGINX. Es handelt sich um eine einzigartige JavaScript-Implementierung für NGINX und NGINX Plus, die speziell für serverseitige Anwendungsfälle und die Verarbeitung einzelner Anfragen entwickelt wurde.
[ Herausgeber – Der folgende Anwendungsfall ist nur einer von vielen für das NGINX JavaScript-Modul. Eine Liste aller Anwendungsfälle finden Sie unter Anwendungsfälle für das NGINX-JavaScript-Modul .
Dieser Beitrag wurde aktualisiert, um das überarbeitete Sitzungsobjekt ( die Sitzungen
) für das in NGINX JavaScript 0.2.4 eingeführte Stream-Modul und die in NGINX JavaScript 0.4.0 eingeführte js_import-
Direktive zu verwenden. ]
Innerhalb des Stream-Moduls für TCP/UDP-Lastausgleich bietet NGINX JavaScript Zugriff auf den Inhalt von Anforderungs- und Antwortpaketen. Das heißt, wir können die Client-Anfrage entsprechend der SQL-Abfrage untersuchen und nützliche Elemente wie die SQL-Methode extrahieren, zum Beispiel SELECT
oder UPDATE
. NGINX JavaScript kann solche Werte dann als reguläre NGINX-Variablen verfügbar machen. In diesem Beispiel fügen wir unseren JavaScript-Code in /etc/nginx/sql_method.js ein.
Der Funktion getSqlMethod()
werden ein oder mehrere
JavaScript-Objekte übergeben, die das aktuelle Paket darstellen. Eigenschaften dieses Objekts wie „fromUpstream“
und „Buffer“
liefern uns die benötigten Informationen über das Paket und seinen Kontext.
Wir prüfen zunächst, ob das TCP-Paket vom Client kommt, da wir Pakete, die vom Upstream-MySQL-Server kommen, nicht untersuchen müssen. Hier interessiert uns das dritte Client-Paket, da die ersten beiden Pakete Handshake- und Authentifizierungsinformationen enthalten. Das dritte Client-Paket enthält die SQL-Abfrage. Der Anfang dieser Zeichenfolge wird dann mit einer der im Methoden
-Array definierten SQL-Methoden verglichen. Wenn wir eine Übereinstimmung finden, speichern wir das Ergebnis in der globalen Variable $method
und schreiben einen Eintrag in das Fehlerprotokoll. Die NGINX-JavaScript-Protokollierung wird in das Fehlerprotokoll unter „Schweregradinformationen
“ geschrieben und wird daher standardmäßig nicht angezeigt.
Die Funktion setSqlMethod()
wird aufgerufen, wenn eine gleichnamige NGINX-Variable ausgewertet wird. In diesem Fall wird die Variable mit der globalen NGINX-JavaScript-Variable $method
gefüllt, die aus Aufrufen der Funktion getSqlMethod()
gewonnen wurde.
Beachten Sie, dass dieser NGINX-JavaScript-Code für den MySQL-Befehlszeilenclient entwickelt wurde, wo eine einzelne Abfrage ausgeführt wird. Es erfasst komplexe Abfragen oder mehrere Abfragen über eine langlebige Verbindung nicht genau, obwohl der Code für diese Anwendungsfälle angepasst werden könnte. Anweisungen zum Installieren und Aktivieren des NGINX-JavaScript-Moduls finden Sie im NGINX Plus-Administratorhandbuch .
Um die SQL-Methode in unsere Protokolle aufzunehmen, schließen wir die Variable $sql_method
in die Direktive log_format
ein.
Wir müssen unsere Konfiguration auch erweitern, um NGINX Plus mitzuteilen, wie und wann der NGINX-JavaScript-Code ausgeführt werden soll.
Zuerst geben wir den Speicherort des NGINX-JavaScript-Codes mit der Direktive „js_import“
an und verwenden die Direktive „js_set“
, um NGINX Plus anzuweisen, die Funktion „setSqlMethod()“
aufzurufen, wenn die Variable „$sql_method“
ausgewertet werden muss. Anschließend verwenden wir im Server{}-
Block die Direktive js_filter
, um die Funktion anzugeben, die bei jeder Verarbeitung eines Pakets aufgerufen wird. Optional können wir die Direktive error_log
mit der Option info
hinzufügen, um die NGINX-JavaScript-Protokollierung zu aktivieren.
Mit dieser zusätzlichen Konfiguration sieht unser Zugriffsprotokoll jetzt so aus.
$ tail -3 /var/log/nginx/galera_access.log 192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 1611 127.0.0.1:33063 0.000 0.003 12.614 12.614 UPDATE 192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 8337 127.0.0.1:33061 0.001 0.001 11.181 11.181 SELECT 192.168.91.1 [23/Jul/2021:17:42:19 +0100] TCP 200 369 1611 127.0.0.1:33062 0,001 0,001 10,460 10,460 AKTUALISIEREN
[ Herausgeber – Dieser Abschnitt wurde aktualisiert, um auf die NGINX Plus-API zu verweisen, die das ursprünglich hier besprochene separate erweiterte Statusmodul ersetzt und veraltet. ]
Wir können nicht nur die MySQL-Aktivität detailliert protokollieren, sondern auch Echtzeitmetriken und den Zustand unserer Upstream-MySQL-Server auf dem NGINX Plus-Dashboard zur Live-Aktivitätsüberwachung beobachten (NGINX Open Source bietet einen kleineren Satz von Metriken und nur über die Stub Status API ).
Das NGINX Plus-Dashboard wurde in NGINX Plus R7 eingeführt und bietet eine Webschnittstelle zur NGINX Plus-API . Wir aktivieren dies, indem wir in einer separaten Datei /etc/nginx/conf.d/dashboard.conf einen neuen Server{}-
Block im http-
Kontext hinzufügen:
Wir müssen außerdem den Server{}-
Block in stream.conf mit der Direktive status_zone
aktualisieren, um die Erfassung von Überwachungsdaten für unseren MySQL-Dienst zu ermöglichen.
Mit dieser Konfiguration ist das NGINX Plus-Dashboard auf Port 8080 verfügbar. Im folgenden Screenshot sehen wir unsere drei MySQL-Server, von denen jeder die Details zahlreicher laufender Verbindungen und den aktuellen Integritätsstatus anzeigt. Wir können sehen, dass der Knoten, der auf Port 33062 lauscht, zuvor einen kurzen Ausfall von 18,97 Sekunden hatte (gemeldet in der DT- Spalte).
Galera Cluster stellt jeden MySQL-Serverknoten als Masterdatenbank dar, die sowohl Lese- als auch Schreibvorgänge ausführt. Bei vielen Anwendungen ist das Verhältnis zwischen Lese- und Schreibvorgängen so groß, dass das Risiko, dass dieselbe Tabellenzeile von mehreren Clients gleichzeitig aktualisiert wird, im Vergleich zur Flexibilität, die ein Multimaster-Datenbankcluster bietet, völlig akzeptabel ist. In Situationen, in denen ein höheres Risiko gleichzeitiger Schreibvorgänge besteht, haben wir zwei Optionen.
In diesem Artikel haben wir einige der wesentlichen Aspekte des Lastenausgleichs einer TCP- (oder UDP-)Anwendung wie MySQL untersucht. NGINX Plus bietet einen voll funktionsfähigen TCP/UDP-Load Balancer, der Ihnen hilft, Anwendungen mit Leistung, Zuverlässigkeit, Sicherheit und Skalierbarkeit bereitzustellen – unabhängig von der Art des Datenverkehrs.
Um NGINX Plus auszuprobieren, starten Sie noch heute Ihre kostenlose 30-Tage-Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen.
Die Testumgebung wird auf einer virtuellen Maschine installiert, sodass sie isoliert und wiederholbar ist. Es gibt jedoch keinen Grund, warum es nicht auf einem physischen „Bare-Metal“-Server installiert werden kann.
Siehe das NGINX Plus-Administratorhandbuch .
In diesem Beispiel installieren wir Galera Cluster auf einem einzelnen Host und verwenden Docker-Container für jeden Knoten. Die folgenden Anweisungen basieren auf „Erste Schritte mit Galera mit Docker“ und setzen voraus, dass sowohl die Docker Engine als auch das MySQL-Befehlszeilentool bereits installiert sind.
Erstellen Sie eine grundlegende MySQL-Konfigurationsdatei ( my.cnf ), die vom Docker-Image in jeden Galera-Container kopiert wird.
Ziehen Sie das grundlegende Docker-Image von Galera.
$ sudo docker pull erkules/galera:basic
Erstellen Sie den ersten Galera-Knoten ( Knoten1 ) und legen Sie den MySQL-Standardport als 33061 fest.
$ sudo docker run -p 33061:3306 --detach=true --name node1 -h node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://
Erstellen Sie den zweiten Galera-Knoten ( node2 ). Der MySQL-Port wird als 33062 angezeigt und für die Kommunikation zwischen Clustern mit Knoten1 verknüpft.
$ sudo docker run -p 33062:3306 --detach=true --name node2 -h node2 --link node1:node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://node1
Erstellen Sie den dritten und letzten Galera-Knoten ( node3 ) auf die gleiche Weise wie node2 . Der MySQL-Port wird als 33063 angezeigt.
$ sudo docker run -p 33063:3306 --detach=true --name node3 -h node3 --link node1:node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://node1
Erstellen Sie ein Benutzerkonto namens nginx , das für den Remotezugriff auf den Cluster vom Host aus verwendet werden kann. Dies wird durch Ausführen des Befehls mysql(1)
innerhalb des Docker-Containers selbst erreicht.
$ sudo docker exec -ti node1 mysql -e „GEWÄHREN SIE ALLE PRIVILEGIEN FÜR *.* AN ‚nginx‘@‚172.17.0.1‘, IDENTIFIZIERT DURCH ‚plus‘“
Überprüfen Sie, ob Sie vom Host aus mithilfe des TCP-Protokolls eine Verbindung zum Galera-Cluster herstellen können.
$ mysql --protocol=tcp -P 33061 --user=nginx --password=plus -e "SHOW DATABASES" mysql: [Warnung] Die Verwendung eines Passworts in der Befehlszeilenschnittstelle kann unsicher sein. +--------------------+ | Datenbank | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+
Führen Sie abschließend denselben Befehl für einen anderen Clusterknoten aus, um zu zeigen, dass das Nginx- Benutzerkonto repliziert wurde und der Cluster ordnungsgemäß funktioniert.
$ mysql --protocol=tcp -P 33062 --user=nginx --password=plus -e "SHOW DATABASES" mysql: [Warnung] Die Verwendung eines Passworts in der Befehlszeilenschnittstelle kann unsicher sein. +--------------------+ | Datenbank | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+
„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."