Heim > Artikel > Betrieb und Instandhaltung > So optimieren Sie Nginx und Node.js für Netzwerke mit hoher Auslastung
Netzwerkoptimierung
Wenn Sie nicht zunächst die zugrunde liegenden Übertragungsmechanismen von Nginx und Node.js verstehen und eine gezielte Optimierung durchführen, ist die Optimierung der beiden, egal wie detailliert sie ist, umsonst. Normalerweise verbindet Nginx den Client und die Upstream-Anwendungen über einen TCP-Socket.
Unser System verfügt über viele Schwellenwerte und Einschränkungen für TCP, die über Kernel-Parameter festgelegt werden. Die Standardwerte dieser Parameter werden häufig für allgemeine Zwecke festgelegt und können den Anforderungen von Webservern an hohen Datenverkehr und kurze Lebensdauer nicht gerecht werden.
Hier sind einige Parameter, die als Kandidaten für die Optimierung von TCP verwendet werden können. Um sie wirksam zu machen, können Sie sie in die Datei /etc/sysctl.conf oder in eine neue Konfigurationsdatei wie /etc/sysctl.d/99-tuning.conf einfügen und dann sysctl -p ausführen Lassen Sie den Kernel sie laden. Wir verwenden sysctl-cookbook, um diese physische Arbeit zu erledigen.
Es ist zu beachten, dass die hier aufgeführten Werte sicher zu verwenden sind. Es wird jedoch dennoch empfohlen, die Bedeutung jedes Parameters zu studieren, um einen geeigneteren Wert basierend auf Ihrer Last, Hardware und Nutzung auszuwählen.
Code kopieren Der Code lautet wie folgt:
net.ipv4.ip_local_port_range='1024 65000'
net.ipv4 .tcp_tw_reuse='1'
net.ipv4.tcp_fin_timeout='15'
net.core.netdev_max_backlog='4096'
net.core.rmem_max='16777216'
net.core.somaxconn='4096'
Net.core ='40 96 87380 span>
Heben Sie einige davon hervor. Eine wichtige.
net.ipv4.ip_local_port_range
Um den Downstream-Client für die Upstream-Anwendung zu bedienen, muss Nginx zwei TCP-Verbindungen öffnen, eine zum Client und eine zur Anwendung. Wenn ein Server viele Verbindungen empfängt, sind die verfügbaren Ports des Systems schnell erschöpft. Durch Ändern des Parameters net.ipv4.ip_local_port_range können Sie den Bereich der verfügbaren Ports vergrößern. Wenn in /var/log/syslog ein solcher Fehler gefunden wird: „Mögliches Syn-Flooding auf Port 80. Senden von Cookies“, bedeutet dies, dass das System keinen verfügbaren Port finden kann. Durch Erhöhen des Parameters net.ipv4.ip_local_port_range kann dieser Fehler reduziert werden.
net.ipv4.tcp_tw_reuse
Wenn der Server zwischen einer großen Anzahl von TCP-Verbindungen wechseln muss, wird eine große Anzahl von Verbindungen im Status „time_wait“ generiert. time_wait bedeutet, dass die Verbindung selbst geschlossen ist, die Ressourcen jedoch nicht freigegeben wurden. Wenn Sie net_ipv4_tcp_tw_reuse auf 1 setzen, kann der Kernel versuchen, Verbindungen wiederzuverwenden, wenn dies sicher ist. Dies ist viel kostengünstiger als die Wiederherstellung neuer Verbindungen.
Dies ist die Mindestzeit, die eine Verbindung im Status „time_wait“ warten muss, bevor sie wiederhergestellt wird. Eine Verkleinerung kann das Recycling beschleunigen. So überprüfen Sie den Verbindungsstatus
Verwenden Sie netstat:
netstat -tan | (Kernel 541)
tcp: 47461 (ESTAB 311, geschlossen 47135, OrphaNed 4, Synrecv 0, Timewait 47135/0), Ports 33938
Transport Total IP IPv6
* 541 - -
raw 0 0 Ut 13 10 3
tcp 326 325 1inet 339 335 4
frag 0 0 0
Wenn die Auslastung des Webservers allmählich zunimmt, werden wir auf einige seltsame Einschränkungen von Nginx stoßen. Die Verbindung wird unterbrochen und der Kernel meldet weiterhin Syn-Flood. Zu diesem Zeitpunkt sind der Lastdurchschnitt und die CPU-Auslastung sehr gering, und der Server kann offensichtlich mehr Verbindungen verarbeiten, was wirklich frustrierend ist.
Nach einer Untersuchung haben wir festgestellt, dass es im time_wait-Zustand viele Verbindungen gibt. Hier ist die Ausgabe von einem der Server:
Es gibt 47135 time_wait-Verbindungen! Darüber hinaus ist aus ss ersichtlich, dass es sich bei allen um geschlossene Verbindungen handelt. Dies weist darauf hin, dass der Server die meisten verfügbaren Ports verbraucht hat, und impliziert auch, dass der Server jeder Verbindung neue Ports zuweist. Das Optimieren des Netzwerks half ein wenig bei der Lösung des Problems, aber es waren immer noch nicht genügend Ports vorhanden.
Nach weiteren Recherchen habe ich ein Dokument über die Keepalive-Anweisung für Upstream-Verbindungen gefunden, in dem es heißt:
Legen Sie die maximale Anzahl inaktiver Keepalive-Verbindungen zum Upstream-Server fest. Diese Verbindungen werden im Cache des Arbeitsprozesses gespeichert.
Interessant. Theoretisch minimiert dieses Setup die Verschwendung von Verbindungen, indem Anfragen über zwischengespeicherte Verbindungen weitergeleitet werden. In der Dokumentation wird auch erwähnt, dass wir „proxy_http_version“ auf „1.1“ setzen und den „connection“-Header löschen sollten. Nach weiteren Recherchen habe ich festgestellt, dass dies eine gute Idee ist, da http/1.1 die Nutzung von TCP-Verbindungen im Vergleich zu http1.0 erheblich optimiert und Nginx standardmäßig http/1.0 verwendet.
Nach der Änderung wie im Dokument vorgeschlagen sieht unsere Uplink-Konfigurationsdatei folgendermaßen aus:
Kopieren Sie den Code. Der Code lautet wie folgt:
upstream backend_nodejs {
server nodejs-3:5016 max_fails=0 fail_timeout=10s;
server nodejs-4:5016 max_fails=0 fail_timeout=10s;
server nodejs-5:5016 max_fails=0 fail_timeout=10s;
server nodejs- 6:5016 max_fails=0 fail_timeout=10s;
keepalive 512;
}
Ich habe auch die Proxy-Einstellungen im Serverbereich wie vorgeschlagen geändert. Gleichzeitig wurde ein Proxy_next_upstream hinzugefügt, um ausgefallene Server zu überspringen, das Keepalive_Timeout des Clients angepasst und das Zugriffsprotokoll deaktiviert. Die Konfiguration sieht folgendermaßen aus:
Code kopieren Der Code lautet wie folgt:
server {
listen 80;
server_name fast.gosquared.com;
client_max_body_size 16m;
keepalive_timeout 10;
location / {
proxy_next_upstream error timeout http_500 http_50 2 http_503 http_504;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://backend_nodejs;
}
access_log off;
error_log /dev/null crit;
}
Nachdem ich die neue Konfiguration übernommen habe, habe ich das gefunden Die von den Servern belegten Sockets gingen um 90 % zurück. Anfragen können jetzt über deutlich weniger Verbindungen übermittelt werden. Die neue Ausgabe lautet wie folgt:
ss -s
total: 558 (kernel 604)
tcp: 4675 (estab 485, geschlossen 4183, verwaist 0, synrecv 0, timewait 4183/0), ports 2768
transport total ip ipv6
* 604 - -
raw 0 0 0
udp 13 10 3
tcp 492 491 1
inet 505 501 4
node.js
Dank des ereignisgesteuerten Designs, das E/A asynchron verarbeiten kann, kann node.js große Mengen verarbeiten Beträge out-of-the-box-Verbindungen und Anfragen. Obwohl es andere Optimierungsmethoden gibt, konzentriert sich dieser Artikel hauptsächlich auf den Prozessaspekt von node.js.
Knoten ist Single-Threaded und verwendet nicht automatisch mehrere Kerne. Mit anderen Worten: Die Anwendung kann nicht automatisch alle Funktionen des Servers nutzen.
Clustering von Knotenprozessen erreichen
Wir können die Anwendung so ändern, dass sie mehrere Threads aufteilt und Daten auf demselben Port empfängt, wodurch die Last über mehrere Kerne verteilt werden kann. Node verfügt über ein Cluster-Modul, das alle zum Erreichen dieses Ziels erforderlichen Tools bereitstellt. Das Hinzufügen dieser Tools zur Anwendung erfordert jedoch viel manuelle Arbeit. Wenn Sie Express verwenden, verfügt eBay über ein Modul namens Cluster2, das verwendet werden kann.
Kontextwechsel verhindern
Bei der Ausführung mehrerer Prozesse sollten Sie sicherstellen, dass jeder CPU-Kern gleichzeitig nur mit einem Prozess beschäftigt ist. Wenn die CPU n Kerne hat, sollten wir im Allgemeinen n-1 Anwendungsprozesse generieren. Dadurch wird sichergestellt, dass jeder Prozess eine angemessene Zeitspanne erhält, sodass ein Kern frei bleibt, damit der Kernel-Scheduler andere Aufgaben ausführen kann. Wir müssen außerdem sicherstellen, dass grundsätzlich keine anderen Aufgaben außer node.js auf dem Server ausgeführt werden, um CPU-Konflikte zu verhindern.
Wir haben einmal einen Fehler gemacht und zwei node.js-Anwendungen auf dem Server bereitgestellt, und dann hat jede Anwendung n-1 Prozesse geöffnet. Dadurch konkurrieren sie untereinander um die CPU, wodurch die Systemlast stark ansteigt. Obwohl unsere Server alle 8-Core-Maschinen sind, ist der durch den Kontextwechsel verursachte Leistungsaufwand immer noch deutlich zu spüren. Unter Kontextwechsel versteht man das Phänomen, dass die CPU die aktuelle Aufgabe unterbricht, um andere Aufgaben auszuführen. Beim Umschalten muss der Kernel den gesamten Status des aktuellen Prozesses anhalten und dann einen anderen Prozess laden und ausführen. Um dieses Problem zu lösen, haben wir die Anzahl der von jeder Anwendung gestarteten Prozesse reduziert und sie die CPU gerecht teilen lassen. Dadurch ist die Systemlast gesunken:
Bitte beachten Sie das Bild oben, um zu sehen, wie das System funktioniert Die Last (blaue Linie) ist unter die Anzahl der CPU-Kerne (rote Linie) gefallen. Auf anderen Servern haben wir dasselbe gesehen. Da die Gesamtarbeitslast gleich bleibt, können die Leistungsverbesserungen in der obigen Grafik nur auf die Reduzierung der Kontextwechsel zurückgeführt werden.
In keiner bestimmten Reihenfolge:
1 Wenn Leistungsprobleme auftreten und die Berechnung und Verarbeitung auf der Anwendungsebene durchgeführt werden kann, nehmen Sie sie aus der Datenbankebene. Sortieren und Gruppieren sind klassische Beispiele. Es ist immer einfacher, die Leistung auf der Anwendungsebene zu verbessern als auf der Datenbankebene. Genau wie MySQL ist SQLite einfacher zu steuern.
2. Wenn Sie paralleles Rechnen vermeiden können, versuchen Sie es zu vermeiden. Wenn es sich nicht vermeiden lässt, denken Sie daran, dass große Macht auch große Verantwortung mit sich bringt. Versuchen Sie nach Möglichkeit zu vermeiden, direkt auf Threads zu arbeiten. Arbeiten Sie nach Möglichkeit auf einer höheren Abstraktionsebene. In iOS, GCD sind beispielsweise Verteilungs- und Warteschlangenvorgänge Ihre Freunde. Das menschliche Gehirn ist nicht darauf ausgelegt, unendliche temporäre Zustände zu analysieren – das habe ich auf die harte Tour gelernt.
3. Vereinfachen Sie den Zustand so weit wie möglich und lokalisieren Sie ihn so weit wie möglich. An erster Stelle steht die Anwendbarkeit.
4. Kurze und kombinierbare Methoden sind dein bester Freund.
5. Codekommentare sind gefährlich, weil sie leicht veraltet oder irreführend sein können, aber das ist kein Grund, keine Kommentare zu schreiben. Kommentieren Sie keine trivialen Dinge, aber bei Bedarf sind an einigen besonderen Stellen lange strategische Kommentare erforderlich. Deine Erinnerung wird dich verraten, vielleicht morgen früh, vielleicht nach einer Tasse Kaffee.
6. Wenn Sie der Meinung sind, dass ein Anwendungsszenario „in Ordnung“ ist, kann es sein, dass Sie einen Monat später mit Ihrem veröffentlichten Produkt kläglich scheitern. Seien Sie ein Skeptiker, testen Sie, überprüfen Sie.
7. Sprechen Sie im Zweifelsfall mit allen relevanten Personen im Team.
8. Tun Sie das Richtige – Sie wissen normalerweise, was das bedeutet.
9. Ihre Benutzer sind nicht dumm, sie haben einfach nicht die Geduld, Ihre Tastenkombinationen zu verstehen.
10. Wenn ein Entwickler nicht mit der langfristigen Wartung des von Ihnen entwickelten Systems beauftragt ist, seien Sie vorsichtig mit ihm. 80 % des Blutes, des Schweißes und der Tränen werden in der Zeit nach der Veröffentlichung der Software vergossen – dann wird man zum Menschenfeind, aber auch zum schlaueren „Kenner“.
11. To-do-Listen sind dein bester Freund.
12. Ergreifen Sie die Initiative, damit Ihre Arbeit mehr Spaß macht. Manchmal erfordert dies Anstrengung von Ihrer Seite.
13. Stille Zusammenbrüche, von denen ich immer noch aus Albträumen aufwache. Überwachung, Protokollierung, Alarmierung. Seien Sie sich der verschiedenen Fehlalarme und der unvermeidlichen Abstumpfung der Sinne bewusst. Halten Sie Ihr System rechtzeitig auf Ausfälle aufmerksam.
Das obige ist der detaillierte Inhalt vonSo optimieren Sie Nginx und Node.js für Netzwerke mit hoher Auslastung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!