NGINX und NGINX Plus sind extrem leistungsstarke HTTP- , TCP- und UDP- Load Balancer. Sie sind sehr effizient beim Weiterleiten großer Anforderungsmengen und beim Aufrechterhalten einer großen Zahl gleichzeitiger Verbindungen. Aufgrund dieser Eigenschaften sind NGINX und NGINX Plus jedoch besonders anfällig für eine kurzzeitige Port-Erschöpfung – ein Zustand, in dem keine neuen Verbindungen hergestellt werden können, weil dem Betriebssystem nicht genügend Portnummern zum Einrichten neuer lokaler Sockets zugewiesen sind. (Die kurzlebige Port-Erschöpfung betrifft beide Produkte, der Kürze halber beziehen wir uns im weiteren Verlauf dieses Blogs jedoch nur auf NGINX Plus.)
In diesem Blog überprüfen wir die Komponenten einer TCP-Verbindung und wie ihr Inhalt entschieden wird, bevor eine Verbindung hergestellt wird. Anschließend zeigen wir, wie Sie feststellen, wann NGINX Plus von der Erschöpfung temporärer Ports betroffen ist. Abschließend besprechen wir Strategien zum Bekämpfen dieser Einschränkungen mithilfe von Linux-Kernel-Optimierungen und NGINX Plus-Direktiven.
Wenn eine Verbindung über TCP hergestellt wird, wird sowohl auf dem lokalen als auch auf dem Remote-Host ein Socket erstellt. Diese Sockets werden dann verbunden, um ein Socket-Paar zu erstellen, das durch ein eindeutiges 4-Tupel beschrieben wird, das aus der lokalen IP-Adresse und dem Port sowie der Remote-IP-Adresse und dem Port besteht.
Die Remote-IP-Adresse und der Port gehören zur Serverseite der Verbindung und müssen vom Client ermittelt werden, bevor dieser die Verbindung überhaupt herstellen kann. In den meisten Fällen wählt der Client automatisch die für die Verbindung zu verwendende lokale IP-Adresse aus. Manchmal wird die Adresse jedoch von der Software ausgewählt, die die Verbindung herstellt. Abschließend wird der lokale Port per Zufallsprinzip aus einem definierten Bereich ausgewählt, der vom Betriebssystem zur Verfügung gestellt wird. Der Port ist nur für die Dauer der Verbindung mit dem Client verknüpft und wird daher als flüchtig bezeichnet. Wenn die Verbindung beendet wird, steht der temporäre Port zur erneuten Verwendung zur Verfügung.
Wie in der Einleitung erwähnt, ist NGINX Plus naturgemäß einer kurzzeitigen Port-Erschöpfung und den dadurch verursachten Problemen ausgesetzt. Wenn NGINX Plus eine Anfrage an einen Upstream-Server weiterleitet, ist es der Client im oben beschriebenen Socket-Erstellungsprozess und sein Standardverhalten besteht darin, den Socket für die weitergeleitete Anfrage automatisch an eine lokale IP-Adresse und einen flüchtigen Port zu binden, der auf dem Host, auf dem es ausgeführt wird, verfügbar ist. Wenn die Verbindungsrate so hoch ist, dass die herzustellenden Sockets schneller in einen Wartezustand versetzt werden, als vorhandene offene Sockets geschlossen werden, sind die verfügbaren Ports irgendwann erschöpft und es können keine neuen Sockets erstellt werden. Dies führt zu Fehlern sowohl im Betriebssystem als auch bei NGINX Plus. Hier ist ein Beispiel für den resultierenden Fehler im NGINX Plus-Fehlerprotokoll.
2016/03/18 09:08:37 [crit] 1888#1888: *13 connect() zu 10.2.2.77:8081 fehlgeschlagen (99: Angeforderte Adresse kann nicht zugewiesen werden ) während der Verbindung zum Upstream, Client: 10.2.2.42, Server: , Anfrage: "GET / HTTP/1.1", Upstream: "http://10.2.2.77:8081/", Host: „10.2.2.77“
Port-Erschöpfung führt auch zu einem Anstieg der500
Fehler wurden eher von NGINX Plus als vom Upstream-Server verursacht. Hier ist ein Beispieleintrag im NGINX Plus-Zugriffsprotokoll.
10.2.2.42 - - [18/Mar/2016:09:14:20 -0700] "GET / HTTP/1.1"500 192 "-" "curl/7.35.0"
Um die Anzahl der Sockets im Status TIME-WAIT
auf Ihrem NGINX Plus-Server zu überprüfen, führen Sie den folgenden ss
-Befehl in der Linux-Shell aus. Das Beispiel zeigt, dass 143 Sockets mit dem Status TIME-WAIT
geöffnet sind. Im Beispiel ermitteln wir die Anzahl, indem wir den Befehl wc
verwenden, um die Anzahl der Zeilen in der Befehlsausgabe aufzulisten.
# ss -a | grep ZEITWAIT | wc -l143
Eine Möglichkeit, die Erschöpfung temporärer Ports zu reduzieren, ist die Verwendung der Linux-Kernel-Einstellung net.ipv4.ip_local_port_range
. Der Standardbereich liegt üblicherweise zwischen 32768 und 61000.
Wenn Sie feststellen, dass Ihnen die temporären Ports ausgehen, können Sie die Anzahl der verfügbaren temporären Ports in der Praxis verdoppeln, indem Sie den Bereich vom Standardwert auf 1024 bis 65000 ändern. Weitere Informationen zum Ändern der Kerneleinstellungen finden Sie in unserem Blogbeitrag „Tuning von NGINX für die Leistung“ .
Eine weitere Möglichkeit, die Erschöpfung temporärer Ports zu reduzieren, besteht darin, Keepalive-Verbindungen zwischen NGINX Plus und Upstream-Servern zu aktivieren. Bei der einfachsten Implementierung von HTTP öffnet ein Client eine neue Verbindung, schreibt die Anforderung, liest die Antwort und schließt dann die Verbindung, um die zugehörigen Ressourcen freizugeben.
Eine Keepalive-Verbindung bleibt offen, nachdem der Client die Antwort gelesen hat, sodass sie für nachfolgende Anfragen wiederverwendet werden kann.
Verwenden Sie die Keepalive-
Direktive, um Keepalive-Verbindungen von NGINX Plus zu Upstream-Servern zu aktivieren, und definieren Sie die maximale Anzahl inaktiver Keepalive-Verbindungen zu Upstream-Servern, die im Cache jedes Arbeitsprozesses beibehalten werden. Wenn diese Zahl überschritten wird, werden die am wenigsten genutzten Verbindungen geschlossen. Ohne Keepalives entsteht mehr Overhead und die Effizienz sowohl bei Verbindungen als auch bei temporären Ports ist ineffizient.
Die folgende Beispielkonfiguration weist NGINX Plus an, mindestens 128 Keepalive-Verbindungen zu den Servern aufrechtzuerhalten, die im Upstream-
Block mit der Bezeichnung „Backend“ definiert sind.
Upstream-Backend { Server 10.0.0.100:1234;
Server 10.0.0.101:1234;
Keepalive 128;
}
Wenn Sie Keepalive-Verbindungen zu Ihren Upstream-Servern aktivieren, müssen Sie auch die Direktive proxy_http_version
verwenden, um NGINX Plus anzuweisen, HTTP Version 1.1 zu verwenden, und die Direktive proxy_set_header,
um alle Header mit dem Namen Connection
zu entfernen. Beide Anweisungen können in den Konfigurationsblöcken „http“
, „server“
oder „location“
eingefügt werden.
proxy_http_version 1.1; proxy_set_header Verbindung "";
Durch die Optimierung des Kernels und die Aktivierung von Keepalive-Verbindungen lässt sich die Verfügbarkeit und Nutzung flüchtiger Ports deutlich besser kontrollieren. In bestimmten Situationen reichen diese Änderungen jedoch nicht aus, um der übermäßigen Nutzung flüchtiger Ports entgegenzuwirken. In diesem Fall können wir einige NGINX Plus-Direktiven und -Parameter verwenden, die es uns ermöglichen, einen Prozentsatz unserer Verbindungen an statische lokale IP-Adressen zu binden. Dadurch wird die Anzahl der verfügbaren temporären Ports effektiv mit der Anzahl der in der Konfiguration definierten IP-Adressen multipliziert. Um dies zu erreichen, verwenden wir die Anweisungen proxy_bind
und split_clients
.
In der folgenden Beispielkonfiguration legt die Direktive „proxy_bind“
im Standortblock
bei jeder Anfrage die lokale IP-Adresse entsprechend dem Wert der Variable „$split_ip
“ fest. Wir setzen diese Variable dynamisch auf den vom split_clients
-Block generierten Wert, der zur Bestimmung dieses Werts eine Hash-Funktion verwendet.
Der erste Parameter der Direktive split_clients
ist eine Zeichenfolge ( „$remote_addr$remote_port“
), die bei jeder Anforderung mit einer MurmurHash2 -Funktion gehasht wird. Der zweite Parameter ( $split_ip
) ist die Variable, die wir dynamisch basierend auf dem Hash des ersten Parameters festlegen.
Die Anweisungen in den geschweiften Klammern unterteilen die Hash-Tabelle in „Buckets“, von denen jeder einen Prozentsatz der Hashes enthält. Hier teilen wir die Tabelle in 10 Buckets gleicher Größe auf, wir können jedoch eine beliebige Anzahl Buckets erstellen und sie müssen nicht alle gleich groß sein. (Der Prozentsatz für den letzten Bucket wird immer durch ein Sternchen [ * ] und nicht durch eine bestimmte Zahl dargestellt, da die Anzahl der Hashes möglicherweise nicht gleichmäßig in die angegebenen Prozentsätze aufgeteilt werden kann.)
Der Bereich der möglichen Hashwerte reicht von 0 bis 4294967295, sodass in unserem Fall jeder Bucket etwa 429496700 Werte enthält (10 % der Gesamtzahl): der erste Bucket die Werte von 0 bis 429496700, der zweite Bucket von 429496701 bis 858993400 und so weiter. Die Variable $split_ip
wird auf die IP-Adresse eingestellt, die dem Bucket zugeordnet ist, der den Hash der Zeichenfolge $remote_addr$remote_port
enthält. Als konkretes Beispiel fällt der Hash-Wert 150000000 in den vierten Bucket, sodass die Variable $split_ip
in diesem Fall dynamisch auf 10.0.0.213 gesetzt wird.
http { Upstream-Backend { Server 10.0.0.100:1234; Server 10.0.0.101:1234; } Server { # ... Standort / { # ... Proxy-Passwort http://backend; Proxy-Bindung $split_ip; Proxy-Set-Header X-Forwarded-For $remote_addr; } } Split-Clients "$remote_addr$remote_port" $split_ip { 10 % 10.0.0.210; 10 % 10.0.0.211; 10 % 10.0.0.212; 10 % 10.0.0.213; 10 % 10.0.0.214; 10 % 10.0.0.215; 10 % 10.0.0.216; 10 % 10.0.0.217; 10 % 10.0.0.218; * 10.0.0.219; } }
Durch die Optimierung der Linux-Kernel-Einstellung für die Anzahl der temporären Ports wird eine effizientere Verfügbarkeit und Nutzung erreicht. Durch das Aktivieren von Keepalive-Verbindungen von NGINX Plus zu Ihren Upstream-Servern wird deren Nutzung temporärer Ports effizienter. Und schließlich können Sie durch die Verwendung der Anweisungen split_clients
und proxy_bind
in Ihrer NGINX Plus-Konfiguration ausgehende Verbindungen dynamisch an eine definierte Liste lokaler IP-Adressen binden und so die Anzahl der für NGINX Plus verfügbaren temporären Ports erheblich erhöhen.
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."