NGINX Plus R9 führt die Möglichkeit zum Reverse-Proxy und zum Lastenausgleich für UDP-Verkehr ein, eine wesentliche Verbesserung der Layer-4-Lastausgleichsfunktionen von NGINX Plus.
In diesem Blogbeitrag werden die Herausforderungen beim Betrieb eines DNS-Servers in einer modernen Anwendungsinfrastruktur untersucht, um zu veranschaulichen, wie sowohl NGINX Open Source als auch NGINX Plus die Last sowohl des UDP- als auch des TCP-Verkehrs effektiv und effizient ausgleichen können. (Anwendungsintegritätsprüfungen [aktiv] sind exklusiv für NGINX Plus, ansonsten gelten die Informationen in diesem Blog jedoch gleichermaßen für NGINX Open Source; der Kürze halber beziehen wir uns im Rest des Beitrags auf NGINX Plus.)
[Herausgeber – Eine Übersicht über alle neuen Funktionen in NGINX Plus R9 finden Sie unter „Ankündigung von NGINX Plus R9“ in unserem Blog.]
Im Gegensatz zu TCP garantiert UDP konstruktionsbedingt keine End-to-End-Datenübertragung. Es ist vergleichbar mit dem Versenden einer Nachricht per Brieftaube – Sie wissen mit Sicherheit, dass die Nachricht gesendet wurde, können aber nicht sicher sein, dass sie angekommen ist. Dieser „verbindungslose“ Ansatz bietet mehrere Vorteile – vor allem eine geringere Latenz als bei TCP, da die kleineren Einzelnachrichten von UDP weniger Bandbreite verbrauchen und zum Herstellen einer Verbindung kein Handshake-Prozess erforderlich ist. UDP überlässt das Problem der Erkennung von Timeouts und anderen Problemen auf Netzwerkebene dem Anwendungsentwickler. Aber was bedeutet dies für DNS?
Wie mehrere andere UDP-basierte Protokolle verwendet DNS einen Anforderungs-Antwort-Datenfluss. Beispielsweise fragt ein DNS-Client nach der zu einem Hostnamen gehörenden IP-Adresse und erhält eine Antwort. Wenn innerhalb einer bestimmten Zeitspanne keine Antwort eintrifft, sendet der DNS-Client die gleiche Anfrage an einen „Backup“-DNS-Server. Das Abwarten des Timeout-Zeitraums vor dem erneuten Versuch einer Anforderung kann jedoch dazu führen, dass ein normalerweise extrem schneller Prozess (gemessen in Millisekunden) sehr langsam wird (gemessen in Sekunden).
Durch die Verwendung von NGINX Plus zum Proxy und Lastenausgleich des DNS-Verkehrs wird die Anzahl der Fälle verringert, in denen es beim Client zu einem Timeout kommt. Mit mehreren DNS-Servern hinter dem NGINX Plus-Load Balancer kommt es bei Clients nur dann zu einer Zeitüberschreitung, wenn sich zwischen dem Client und NGINX Plus eine Netzwerkpartition befindet. Wenn NGINX Plus Anwendungsintegritätsprüfungen durchführt, treten beim Client keine Probleme mit den DNS-Servern selbst auf. Durch die Überwachung der Verfügbarkeit und Antwortzeit jedes Servers vermeidet NGINX Plus das Senden von Clientanforderungen an einen fehlerhaften Server.
Obwohl der überwiegende Teil des DNS-Verkehrs über UDP läuft, gibt es gängige DNS-Vorgänge, die TCP verwenden. DNS verwendet UDP für kleine Nachrichten (bis zu 512 Bytes), TCP jedoch für Vorgänge, die größere Nachrichten erfordern (oder wahrscheinlich erfordern). Historisch wurde TCP mit DNS nur für Zonenübertragungen von einem autoritativen, primären Nameserver zu seinen sekundären Nameservern verwendet. Mit der Umstellung auf Container und unveränderliche Infrastrukturen wird DNS jedoch zunehmend als primärer Mechanismus zur Diensterkennung verwendet, und zwar durch die Verwendung von SRV-
Einträgen.
DNS- SRV-
Einträge wurden ursprünglich für VoIP-Mobiltelefone (Voice over IP) eingeführt, die SIP zur Erkennung ihrer Server verwenden, können jedoch für jede Art von Dienst verwendet werden. SRV
-Einträge enthalten jedoch viel mehr Informationen als die meisten anderen DNS-Eintragstypen. Daher passen in die standardmäßige 512-Byte-UDP-Antwort nur etwa 10 SRV-
Datensätze, im Gegensatz zu etwa 30 A
-Datensätzen. Wenn eine DNS-Antwort das 512-Byte-Limit überschreitet, werden die ersten 512 Bytes zurückgegeben, die Antwort jedoch als „abgeschnitten“ gekennzeichnet. An diesem Punkt kann ein DNS-Client entweder die gekürzte Antwort so gut wie möglich verarbeiten oder dieselbe Anfrage über TCP wiederholen.
Dies bedeutet, dass NGINX Plus beim Lastenausgleich von DNS-Servern in einer modernen Netzwerkinfrastruktur mit einer Mischung aus UDP- und TCP-Datenverkehr rechnen kann.
Die folgende Abbildung zeigt eine vereinfachte Ansicht einer Microservices-Umgebung mit zwei Load Balancern. Der Front-End-Load Balancer leitet Anfragen von den öffentlichen Clients der Anwendung weiter, wählt die beste Microservice-Instanz aus und führt viele andere Funktionen aus, die wir hier nicht besprechen. Wir konzentrieren uns auf den DNS-Load Balancer, der zwischen der Microservices-Umgebung und den DNS-Servern sitzt, die den Microservices Service-Discovery-Informationen bereitstellen.
NGINX Plus implementiert Layer 4-Lastausgleich im Stream- Modul, sodass UDP- und TCP-Lastausgleich im Stream-
Block wie im folgenden Snippet gezeigt konfiguriert wird.
Warnung: Sie können diesen Konfigurationsausschnitt nicht einfach als neue Datei im Verzeichnis /etc/nginx/conf.d hinzufügen. Es tritt ein Validierungsfehler auf („Stream-Direktive ist hier nicht zulässig“), da die Standardkonfigurationsdatei nginx.conf von NGINX Plus den Inhalt von Dateien im Verzeichnis conf.d im http-
Block einschließt. Die einfachste Lösung besteht darin, den kompletten Stream-
Block direkt in nginx.conf einzubinden.
stream { upstream dns_servers {
Server 192.168.136.130:53;
Server 192.168.136.131:53;
}
Server {
listen 53 udp;
listen 53; #tcp
proxy_pass dns_servers;
error_log /var/log/nginx/dns.log info;
}
}
Zuerst definieren wir die Upstream-Gruppe der DNS-Server. Die Serveranweisungen
geben die Portnummer an, auf der unsere Upstream-Server lauschen, 53 (der bekannte Port für DNS).
Der Server{}-
Block definiert, wie NGINX Plus eingehenden DNS-Verkehr verarbeitet. Die beiden Listen
-Direktiven weisen NGINX Plus an, auf Port 53 sowohl auf UDP- als auch auf TCP-Verkehr zu lauschen. TCP ist das Standardprotokoll der Schicht 4 für das Stream-Modul, daher geben wir es nicht explizit als Parameter an, wie wir es für UDP tun.
Die Proxy_Pass-
Direktive teilt NGINX Plus mit, was mit dem Datenverkehr geschehen soll, auf den es wartet. Hier leiten wir diesen Datenverkehr an die Upstream-Gruppe der DNS-Server weiter. NGINX Plus verwendet automatisch UDP beim Weiterleiten von UDP-Anfragen des Clients an Upstream-Server (und TCP für TCP-Anfragen des Clients), sodass wir das Layer-4-Protokoll in der Upstream-Gruppe nicht explizit angeben müssen.
Es gibt keine access_log-
Direktive im Stream-Modul, da NGINX Plus die Nutzlast von TCP-Segmenten oder UDP-Datagrammen nicht überprüft (wie es dies bei HTTP-Paketen tut). Wir können jedoch den Info-
Parameter der Error_log-
Direktive verwenden, um die Verbindungsverarbeitung und Proxy-Ereignisse zu protokollieren.
[Editor – Die Zugriffsprotokollierung wurde nach der Veröffentlichung dieses Blogs im Stream-Modul in NGINX Open Source 1.11.4 und NGINX Plus R11 aktiviert.]
Um die Verfügbarkeit unserer DNS-Server zu verbessern, können wir noch ein paar Anweisungen hinzufügen und aktive (Anwendungs-)Integritätsprüfungen konfigurieren.
Die erste zusätzliche Direktive ist proxy_responses
, die angibt, wie viele Antworten NGINX Plus für jede per Proxy übermittelte UDP-Anfrage erwartet. In unserem Fall beendet NGINX Plus nach dem Erhalt einer einzelnen Antwort sofort das Warten auf weitere Antworten, wodurch der für diese Sitzung verwendete Speicher und Socket freigegeben werden.
Die zweite zusätzliche Anweisung, proxy_timeout
, bestimmt, wie lange NGINX Plus auf eine Antwort vom Server wartet (hier reduzieren wir die standardmäßigen 10 Minuten auf 1 Sekunde). Wenn NGINX Plus innerhalb dieser Zeitspanne keine Antwort erhält, versucht es den nächsten Server in der Upstream-Gruppe und markiert den nicht reagierenden Upstream-Server für eine festgelegte Zeitspanne (standardmäßig 10 Sekunden) als nicht verfügbar, sodass während dieser Zeit keine anderen Clients eine durch Timeout bedingte Verzögerung erleiden.
Server { abhören 53 udp; abhören 53; #tcp Proxy-Pass DNS-Server; Fehlerprotokoll /var/log/nginx/dns.log Info; Proxy-Antworten 1 ; Proxy-Timeout 1 s ; }
Wir können auch die Zeitspanne ändern, in der ein Server als nicht verfügbar markiert ist, indem wir die Option fail_timeout
in die Serverdirektive
in der Upstream-Gruppe aufnehmen. Mit der folgenden Einstellung markiert NGINX Plus ausgefallene Upstream-Server 60 Sekunden lang als nicht verfügbar:
Upstream-DNS-Server { Server 192.168.136.130:53 Fehlerzeitüberschreitung = 60 s ; Server 192.168.136.131:53 Fehlerzeitüberschreitung = 60 s ; }
Dadurch können wir steuern, wie groß die Verzögerung für einen Client ist, wenn einer unserer DNS-Server ausfällt. Wenn jedoch eine TCP-Anfrage an einen ausgefallenen DNS-Server gesendet wird, ermöglicht die in TCP integrierte Fehlerprüfung NGINX Plus, diesen automatisch als nicht verfügbar zu markieren, sodass nachfolgende TCP- oder UDP-Anfragen an diesen Server vermieden werden.
Die aktive Integritätsprüfungsfunktion in NGINX Plus ist ein zusätzliches und äußerst wertvolles Tool für die Hochverfügbarkeit aller Lastenausgleichsdienste, einschließlich DNS. Anstatt zu warten, bis eine tatsächliche TCP-Anforderung eines DNS-Clients fehlschlägt, bevor der DNS-Server als ausgefallen markiert wird, lassen wir NGINX Plus in regelmäßigen Abständen eine TCP-Verbindung auf Port 53 herstellen, um festzustellen, ob der DNS-Server aktiv ist und ordnungsgemäß funktioniert. Hierzu nehmen wir die Direktive health_check
mit ihrem Parameter port=53
in den Block server{}
auf. (NGINX Plus sendet Integritätschecks standardmäßig an den in der Listen-
Direktive angegebenen Port, in unserem Fall 53. Hier verwenden wir den Parameter, um den Standard explizit zu konfigurieren, aber wir könnten einen anderen Port angeben, wenn wir auch unsere DNS-Server so ändern würden, dass sie auf den Datenverkehr darauf reagieren.)
Mit UDP können wir noch einen Schritt weiter gehen und eine aktive Integritätsprüfung konfigurieren, die eine echte DNS-Suche nach einem bekannten Datensatz durchführt. Beispielsweise könnten wir den folgenden CNAME-
Eintrag in der Zonendatei für dieselbe Subdomäne platzieren, die für die Diensterkennung innerhalb der Microservices-Umgebung verwendet wird.
Gesundheitscheck IN CNAME healthy.svcs.example.com.
Aufgrund der Leichtgewichtigkeit von UDP können wir den Netzwerkverkehr beobachten und problemlos die Bytefolge extrahieren, die eine DNS-Suche darstellt. Dann erstellen wir einen Match-
Konfigurationsblock mit dieser Zeichenfolge als Parameter für die Sendedirektive
. Die „Expect
“-Direktive gibt die Antwort an, die der Server zurückgeben muss, damit er als fehlerfrei gilt.
match dns_lookup {
sende x00x01x00x00x00x01x00x00x00x00x00x00x06x68x65x61 ...;
erwarte ~* "healthy.svcs.example.com.";
}
Der Vorteil dieser umfassenden Integritätsprüfung auf Anwendungsebene besteht darin, dass selbst wenn Ihr Nameserver betriebsbereit ist, durch die Durchführung einer echten DNS-Suche für Ihre Produktionsdomäne Konfigurationsprobleme und Datenbeschädigungen aufgedeckt werden, die andernfalls weiter unten Probleme verursachen könnten.
Das NGINX Plus-Supportteam kann bei der Vorbereitung von UDP-Integritätsprüfungen für DNS-Lookups und andere Protokolle helfen.
Der folgende Codeausschnitt hebt die zusätzlichen Anweisungen hervor, die für aktive Integritätsprüfungen erforderlich sind.
Stream { Upstream-DNS-Server { Zone DNS-Speicher 64 k ; Server 192.168.136.130:53 Fehlerzeitüberschreitung = 60 s; Server 192.168.136.131:53 Fehlerzeitüberschreitung = 60 s; } Übereinstimmung DNS-Lookup { Sende x00x01x00x00x00x01x00x00x00x00x00x00x06x68x65x61 ...; Erwarte ~* „healthy.svcs.example.com.“; } Server { Höre 53 UDP; Höre 53; #TCP Health-Check Übereinstimmung = DNS-Lookup Intervall = 20 Fehler = 2 Durchläufe = 2 UDP; Health-Check Intervall = 20 Fehler = 1 Durchläufe = 2 Port = 53; #TCP Proxy-Pass DNS-Server; Fehlerprotokoll /var/log/nginx/dns.log debug; Proxy-Antworten 1; Proxy-Timeout 1 s; } }
Die Zonendirektive
definiert eine gemeinsam genutzte Speicherzone namens dns_mem , die die Ergebnisse der Integritätsprüfungen (und andere Statusinformationen) allen NGINX Plus-Arbeitsprozessen zur Verfügung stellt.
Die Match-
Direktive wird direkt oben besprochen.
Die Direktive „health_check“
verfügt über eine Reihe von Parametern, die Sie an Ihre Umgebung anpassen können. Hier definieren wir separate Integritätsprüfungen für UDP und TCP. Aufgrund des Unterschieds zwischen UDP und TCP sind bei der UDP-Integritätsprüfung zwei aufeinanderfolgende fehlgeschlagene Versuche erforderlich, bevor der DNS-Server als fehlerhaft markiert wird. Bei TCP hingegen genügt ein Fehler. Für beide Protokolle benötigen wir zwei erfolgreiche Antworten, bevor wir einen Server wieder als fehlerfrei markieren, um das Senden von Anfragen an einen instabilen, „flatternden“ Server zu vermeiden.
Ein Vorteil der Definition einer einzelnen Upstreamgruppe von DNS-Servern für UDP- und TCP-Datenverkehr besteht darin, dass bei einer fehlgeschlagenen Integritätsprüfung für eines der Protokolle der Server als fehlerhaft gekennzeichnet und aus dem Pool mit Lastenausgleich entfernt wird.
Während die Bereitstellung von nur zwei Backend-Servern eine effektive Hochverfügbarkeitslösung sein kann, können Sie mit den Lastausgleichsfunktionen von NGINX Plus Backend-Server horizontal skalieren, ohne dass der Client davon etwas weiß.
Es ist unwahrscheinlich, dass in der oben beschriebenen Beispielumgebung für Microservices eine Skalierung der Back-End-DNS-Server erforderlich ist. Ein ISP, der allen seinen Abonnenten DNS-Dienste zur Verfügung stellt, ist jedoch einer konstanten Auslastung und dem Potenzial für enorme Spitzen ausgesetzt, sodass eine große Anzahl an DNS-Servern und ein Frontend-Proxy zum Lastenausgleich des Datenverkehrs zwischen ihnen erforderlich sind.
Alle Lastausgleichsalgorithmen von NGINX und NGINX Plus sind für TCP und UDP sowie HTTP verfügbar:
(Sie können auch Gewichte für alle Algorithmen konfigurieren, um ihre Effizienz noch weiter zu steigern. Eine Erläuterung hierzu finden Sie im Abschnitt zu Gewichten in „Auswählen einer NGINX Plus-Lastausgleichstechnik“ in unserem Blog.)
Während HTTP-Anfragen hinsichtlich der Belastung und der Verarbeitungsanforderungen an die Backend-Server enorm variieren können, erzeugen DNS-Anfragen typischerweise alle die gleiche Belastung. Aus diesem Grund ist es unwahrscheinlich, dass die Algorithmen „Least Connections“ und „Least Time“ einen Vorteil gegenüber „Round Robin“ bieten. Insbesondere berücksichtigt Least Connections in seiner Verbindungsanzahl alle UDP-Anfragen, für die NGINX Plus noch auf eine Antwort vom Upstream-Server wartet. Solange die Werte für proxy_responses
und proxy_timeout
nicht erreicht sind, zählt NGINX Plus weiterhin Verbindungen für Upstream-Server, die ihre Arbeit möglicherweise bereits abgeschlossen haben.
Wenn Sie über eine große Anzahl von Clients und ein Protokoll verfügen, das viele „Dialogfelder“ ausführt – mehrere Nachrichten, die zwischen Client und Server ausgetauscht werden, wie etwa im RADIUS-Challenge-Response-Flow –, dann ermöglicht die Verwendung eines Quell-IP-Hashes, dass dieser Dialog mit einem einzigen Backend-Server stattfindet. Mit anderen Worten: Es stellt die Sitzungspersistenz her, was bedeutet, dass NGINX Plus alle Anfragen eines bestimmten Clients an denselben Server weiterleitet. Das folgende Beispiel konfiguriert den Hash-Lastausgleichsalgorithmus für ein Paar RADIUS-Authentifizierungsserver, wobei die Quell-(Client-)IP-Adresse (erfasst durch die Variable $remote_addr
) als Schlüssel dient.
upstream radius_servers { hash $remote_addr; # Quell-IP-Hash
Server 192.168.136.201:1812;
Server 192.168.136.202:1812;
}
Weitere Informationen zum UDP- und TCP-Lastausgleich finden Sie in den folgenden Ressourcen:
Upstream-
KonfigurationskontextWeitere Informationen zu den anderen großartigen Funktionen von NGINX Plus R9 finden Sie in unserem Blog unter „Ankündigung von NGINX Plus R9“ und in unserem On-Demand-Webinar „Was ist neu in NGINX Plus R9“ .
Um NGINX Plus auszuprobieren, starten Sie noch heute Ihre kostenlose 30-Tage-Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen.
„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."