BLOG | NGINX

5 Leistungstipps für Node.js-Anwendungen

NGINX-Teil-von-F5-horiz-schwarz-Typ-RGB
Floyd Smith Miniaturbild
Floyd Smith
Veröffentlicht am 16. November 2015
Wenn #nginx nicht vor Ihrem Knotenserver sitzt, machen Sie es wahrscheinlich falsch.
Bryan Hughes auf Twitter

Node.js ist das führende Tool zum Erstellen von Serveranwendungen in JavaScript, der weltweit beliebtesten Programmiersprache. Node.js bietet sowohl die Funktionalität eines Webservers als auch eines Anwendungsservers und gilt heute als zentrales Tool für alle Arten der auf Microservices basierenden Entwicklung und Bereitstellung. (Laden Sie einen kostenlosen Forrester -Bericht zu Node.js und NGINX herunter.)

Node.js kann Java oder .NET für die Entwicklung von Backend-Anwendungen ersetzen oder erweitern.

Node.js ist ein Single-Thread und verwendet nicht blockierende E/A, wodurch es skalierbar ist und Zehntausende gleichzeitige Vorgänge unterstützt. Es hat dieselben Architekturmerkmale wie NGINX und löst das C10K-Problem – die Unterstützung von mehr als 10.000 gleichzeitigen Verbindungen –, zu dessen Lösung NGINX ebenfalls erfunden wurde. Node.js ist für seine hohe Leistung und Entwicklerproduktivität bekannt.

Was könnte also möglicherweise schiefgehen?

Node.js weist einige Schwachstellen und Sicherheitslücken auf, die bei Node.js-basierten Systemen zu Leistungseinbußen oder sogar Abstürzen führen können. Wenn der Datenverkehr einer Node.js-basierten Webanwendung schnell zunimmt, treten häufiger Probleme auf.

Darüber hinaus ist Node.js ein großartiges Tool zum Erstellen und Ausführen von Anwendungslogik, die den zentralen, variablen Inhalt für Ihre Webseite erstellt. Für die Bereitstellung statischer Inhalte – beispielsweise Bilder und JavaScript-Dateien – oder für den Lastenausgleich zwischen mehreren Servern ist es jedoch nicht so ideal.

Um Node.js optimal zu nutzen, müssen Sie statische Inhalte zwischenspeichern, einen Proxy und einen Lastenausgleich zwischen mehreren Anwendungsservern durchführen und Portkonflikte zwischen Clients, Node.js und Helfern, wie z. B. Servern, auf denen Socket.IO ausgeführt wird, verwalten. NGINX kann für all diese Zwecke verwendet werden und ist daher ein großartiges Tool zur Leistungsoptimierung von Node.js.

Verwenden Sie diese Tipps, um die Leistung von Node.js-Anwendungen zu verbessern:

  1. Implementieren Sie einen Reverse-Proxy-Server
  2. Zwischenspeichern statischer Dateien
  3. Lastenausgleich des Datenverkehrs über mehrere Server hinweg
  4. Proxy-WebSocket-Verbindungen
  5. Implementieren Sie SSL/TLS und HTTP/2

Notiz: Eine schnelle Lösung für die Leistung von Node.js-Anwendungen besteht darin, Ihre Node.js-Konfiguration zu ändern, um die Vorteile moderner Multi-Core-Server zu nutzen. Sehen Sie sich die Node.js-Dokumentation an, um zu erfahren, wie Sie Node.js dazu bringen, separate untergeordnete Prozesse zu erzeugen – entsprechend der Anzahl der CPUs auf Ihrem Webserver. Jeder Prozess findet dann auf magische Weise ein Zuhause auf genau einer der CPUs, was zu einer deutlichen Leistungssteigerung führt.

Tipp 1 – Implementieren Sie einen Reverse-Proxy-Server

Wir bei NGINX, Inc. sind immer ein wenig entsetzt, wenn wir Anwendungsserver sehen, die direkt dem eingehenden Internetverkehr ausgesetzt sind und den Kern von Hochleistungssites bilden. Hierzu zählen beispielsweise viele WordPress‑basierte Sites sowie Node.js‑Sites.

Node.js ist in stärkerem Maße als die meisten Anwendungsserver auf Skalierbarkeit ausgelegt und kann auf seiner Webserverseite relativ gut eine Menge Internetverkehr bewältigen. Doch die Bereitstellung von Webinhalten ist nicht der eigentliche Zweck von Node.js – es wurde nicht dafür entwickelt.

Wenn Sie über eine Site mit hohem Datenverkehr verfügen, besteht der erste Schritt zur Verbesserung der Anwendungsleistung darin, einen Reverse-Proxy-Server vor Ihren Node.js-Server zu stellen. Dies schützt den Node.js-Server vor direktem Kontakt mit dem Internetverkehr und ermöglicht Ihnen ein hohes Maß an Flexibilität bei der Verwendung mehrerer Anwendungsserver, beim Lastenausgleich zwischen den Servern und beim Zwischenspeichern von Inhalten.

Ein zentraler Anwendungsfall für NGINX, der von zig Millionen Websites auf der ganzen Welt implementiert wird, besteht darin, NGINX als Reverse-Proxy-Server vor eine vorhandene Serverkonfiguration zu setzen und anschließend weitere Verwendungsmöglichkeiten zu nutzen.

Die Verwendung von NGINX als Reverse-Proxy-Server für Node.js bietet bestimmte Vorteile, darunter:

  • Vereinfachung der Berechtigungsverwaltung und Portzuweisung
  • Effizientere Bereitstellung statischer Bilder (siehe nächster Tipp )
  • Node.js-Abstürze erfolgreich verwalten
  • Abwehr von DoS-Angriffen

Notiz : Diese Tutorials erklären, wie man NGINX als Reverse-Proxy-Server in Ubuntu 14.04- oder CentOS- Umgebungen verwendet, und sie bieten einen nützlichen Überblick für jeden, der NGINX vor Node.js setzt.

Tipp 2 – Statische Dateien zwischenspeichern

Mit zunehmender Nutzung einer auf Node.js basierenden Site wird die Belastung des Servers deutlich. An diesem Punkt möchten Sie zwei Dinge tun:

  1. Holen Sie das Beste aus dem Node.js-Server heraus
  2. Erleichtern Sie das Hinzufügen von Anwendungsservern und den Lastenausgleich zwischen ihnen

Dies ist eigentlich ganz einfach. Beginnen Sie mit der Implementierung von NGINX als Reverse-Proxy-Server, wie im vorherigen Tipp beschrieben. Dies erleichtert die Implementierung von Caching, Lastausgleich (wenn Sie mehrere Node.js-Server haben) und mehr.

Auf der Website von Modulus, einer Anwendungscontainerplattform, gibt es einen hilfreichen Artikel zum Thema Leistungssteigerung von Node.js-Anwendungen mit NGINX. Da Node.js die ganze Arbeit alleine erledigt, konnte die Site des Autors durchschnittlich fast 900 Anfragen pro Sekunde verarbeiten. Mit NGINX als Reverse-Proxy-Server, der statische Inhalte bereitstellt, verarbeitete dieselbe Site mehr als 1600 Anfragen pro Sekunde – eine Leistungssteigerung von fast dem Doppelten.

Durch die Verdoppelung der Leistung gewinnen Sie Zeit, um zusätzliche Schritte zu unternehmen, die weiteres Wachstum ermöglichen, z. B. das Überprüfen (und ggf. Verbessern) Ihres Site-Designs, das Optimieren Ihres Anwendungscodes und das Bereitstellen zusätzlicher Anwendungsserver.

Nachfolgend sehen Sie den Konfigurationscode, der für eine Website funktioniert, die auf Modulus ausgeführt wird:

Server { listen 80;
Servername static-test-47242.onmodulus.net;

root /mnt/app;
Index index.html index.htm;

Standort /static/ {
try_files $uri $uri/ =404;
}

Standort /api/ {
Proxy-Pass http://node-test-45750.onmodulus.net;
}
}

In diesem ausführlichen Artikel von Patrick Nommensen von NGINX, Inc. wird erklärt, wie er statische Inhalte aus seinem persönlichen Blog zwischenspeichert, das auf der Open-Source-Blogging-Plattform Ghost, einer Node.js-Anwendung, läuft. Obwohl einige Details Ghost-spezifisch sind, können Sie einen Großteil des Codes für andere Node.js-Anwendungen wiederverwenden.

Beispielsweise möchten Sie im NGINX- Standortblock wahrscheinlich einige Inhalte vom Cache ausnehmen. Normalerweise möchten Sie beispielsweise die Verwaltungsoberfläche einer Blogging-Plattform nicht zwischenspeichern. Hier ist der Konfigurationscode, der das Caching der Ghost-Verwaltungsschnittstelle deaktiviert (oder ausnimmt):

Standort ~ ^/(?:ghost|signout) { proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control „kein Cache, privat, kein Speicher,
muss erneut validiert werden, max-stale=0, Post-Check=0, Pre-Check=0“;
}

Allgemeine Informationen zum Bereitstellen statischer Inhalte finden Sie im NGINX Plus Admin Guide . Der Admin Guide enthält Konfigurationshinweise, mehrere Reaktionsoptionen auf erfolgreiche oder fehlgeschlagene Versuche, eine Datei zu finden, sowie Optimierungsansätze für eine noch schnellere Leistung.

Durch das Caching statischer Dateien auf dem NGINX-Server wird der Node.js-Anwendungsserver erheblich entlastet und erreicht dadurch eine deutlich höhere Leistung.

Tipp 3 – Implementieren Sie einen Node.js Load Balancer

Der eigentliche Schlüssel zu einer hohen – das heißt nahezu unbegrenzten – Leistung für Node.js-Anwendungen besteht darin, mehrere Anwendungsserver auszuführen und die Last auf alle zu verteilen.

Die Lastverteilung bei Node.js kann besonders schwierig sein, da Node.js ein hohes Maß an Interaktion zwischen JavaScript-Code, der im Webbrowser ausgeführt wird, und JavaScript-Code, der auf dem Node.js-Anwendungsserver ausgeführt wird, ermöglicht, wobei JSON-Objekte als Medium für den Datenaustausch dienen. Dies bedeutet, dass eine bestimmte Client-Sitzung kontinuierlich auf einem bestimmten Anwendungsserver ausgeführt wird und die Sitzungspersistenz bei mehreren Anwendungsservern naturgemäß schwierig zu erreichen ist.

Einer der größten Vorteile des Internets und des Webs ist ihr hoher Grad an Zuständenlosigkeit, was die Fähigkeit einschließt, dass Client-Anfragen von jedem Server erfüllt werden können, der Zugriff auf eine angeforderte Datei hat. Node.js unterbindet Zustandslosigkeit und funktioniert am besten in einer zustandsbehafteten Umgebung, in der derselbe Server durchgängig auf Anfragen von beliebigen spezifischen Clients antwortet.

Diese Anforderung kann am besten durch NGINX Plus erfüllt werden, nicht durch NGINX Open Source. Die beiden Versionen von NGINX sind recht ähnlich, ein wesentlicher Unterschied besteht jedoch in der Unterstützung unterschiedlicher Lastausgleichsalgorithmen.

NGINX unterstützt zustandslose Lastausgleichsmethoden :

  • Round Robin – Eine neue Anfrage geht an den nächsten Server in einer Liste.
  • Wenigste Verbindungen – Eine neue Anfrage geht an den Server mit den wenigsten aktiven Verbindungen.
  • IP-Hash – Eine neue Anfrage wird an den Server gesendet, dem ein Hash der IP-Adresse des Clients zugewiesen ist.

Nur eine dieser Methoden, IP Hash, sendet die Anfragen eines bestimmten Clients zuverlässig an denselben Server, was Node.js-Anwendungen zugutekommt. Allerdings kann IP-Hash leicht dazu führen, dass ein Server eine unverhältnismäßig große Zahl von Anfragen erhält, was zu Lasten anderer Server geht, wie in diesem Blogbeitrag über Techniken zum Lastenausgleich beschrieben. Diese Methode unterstützt die Zustandsbehaftetheit auf Kosten einer möglicherweise nicht optimalen Zuweisung von Anforderungen zu den Serverressourcen.

Im Gegensatz zu NGINX unterstützt NGINX Plus die Sitzungspersistenz . Bei Verwendung der Sitzungspersistenz empfängt derselbe Server zuverlässig alle Anforderungen eines bestimmten Clients. Die Vorteile von Node.js mit seiner zustandsbehafteten Kommunikation zwischen Client und Server und NGINX Plus mit seiner erweiterten Lastausgleichsfunktion werden maximiert.

Sie können also NGINX oder NGINX Plus verwenden, um den Lastausgleich über mehrere Node.js-Server hinweg zu unterstützen. Allerdings erreichen Sie wahrscheinlich nur mit NGINX Plus sowohl eine maximale Lastausgleichsleistung als auch eine Node.js-freundliche Zustandsbeschränkung. Auch die in NGINX Plus integrierten Funktionen zur Überprüfung der Anwendungsintegrität und Überwachung sind hier hilfreich.

NGINX Plus unterstützt auch Session Draining , wodurch ein Anwendungsserver aktuelle Sitzungen ordnungsgemäß beenden kann, nachdem er aufgefordert wurde, sich selbst außer Dienst zu stellen.

Tipp 4 – Proxy-WebSocket-Verbindungen

HTTP ist in allen Versionen für die „Pull“-Kommunikation konzipiert, bei der der Client Dateien vom Server anfordert. WebSocket ist ein Tool zum Aktivieren von „Push“- und „Push/Pull“-Kommunikation, bei dem der Server proaktiv Dateien senden kann, die der Client nicht angefordert hat.

Das WebSocket-Protokoll erleichtert die Unterstützung einer robusteren Interaktion zwischen Client und Server bei gleichzeitiger Reduzierung der übertragenen Datenmenge und Minimierung der Latenz. Bei Bedarf kann eine Vollduplex-Verbindung hergestellt werden, bei der Client und Server je nach Bedarf Anfragen initiieren und empfangen.

Das WebSocket-Protokoll verfügt über eine robuste JavaScript-Schnittstelle und passt daher natürlich zu Node.js als Anwendungsserver – und bei Webanwendungen mit moderatem Transaktionsvolumen auch als Webserver. Bei steigendem Transaktionsvolumen ist es sinnvoll, NGINX zwischen den Clients und dem Node.js-Webserver einzufügen und NGINX oder NGINX Plus zum Zwischenspeichern statischer Dateien und zum Lastenausgleich zwischen mehreren Anwendungsservern zu verwenden.

Node.js wird häufig in Verbindung mit Socket.IO verwendet – einer WebSocket-API, die für die Verwendung zusammen mit Node.js-Anwendungen recht beliebt geworden ist. Dies kann dazu führen, dass Port 80 (für HTTP) oder Port 443 (für HTTPS) stark ausgelastet sind. Die Lösung besteht in der Verwendung eines Proxys zum Socket.IO-Server. Sie können NGINX wie oben beschrieben für den Proxyserver verwenden und erhalten außerdem zusätzliche Funktionen wie statisches Datei-Caching, Lastausgleich und mehr.

Nachfolgend finden Sie Code für eine server.js-Node-Anwendungsdatei, die auf Port 5000 lauscht. Es fungiert als Proxyserver (nicht als Webserver) und leitet Anfragen an den richtigen Port weiter:

var io = require('socket.io').listen(5000); 
io.sockets.on('connection', function (socket) {
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});

socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat-Nachricht von ', name);
});
});
});

Fügen Sie in Ihrer Datei index.html den folgenden Code hinzu, um eine Verbindung zu Ihrer Serveranwendung herzustellen und einen WebSocket zwischen der Anwendung und dem Browser des Benutzers zu instanziieren:

<script src="/socket.io/socket.io.js"></script><script>// <![CDATA[
var socket = io(); // hier Ihr Initialisierungscode.
// ]]>
</script>

Vollständige Anweisungen, einschließlich der NGINX-Konfiguration, finden Sie in unserem Blogbeitrag zur Verwendung von NGINX und NGINX Plus mit Node.js und Socket.IO . Weitere Informationen zu potenziellen Architektur- und Infrastrukturproblemen bei Webanwendungen dieser Art finden Sie in unserem Blogbeitrag zu Echtzeit-Webanwendungen und WebSocket.

Tipp 5 – Implementieren Sie SSL/TLS und HTTP/2

Immer mehr Websites verwenden SSL/TLS, um alle Benutzerinteraktionen auf der Site zu sichern. Es ist Ihre Entscheidung, ob und wann Sie diesen Schritt machen. Wenn Sie ihn machen, unterstützt NGINX den Übergang auf zwei Arten:

  1. Sie können eine SSL/TLS-Verbindung zum Client in NGINX beenden, sobald Sie NGINX als Reverse-Proxy eingerichtet haben. Der Node.js-Server sendet und empfängt unverschlüsselte Anfragen und Inhalte hin und her mit dem NGINX-Reverse-Proxy-Server.
  2. Erste Anzeichen deuten darauf hin, dass die Verwendung von HTTP/2 , der neuen Version des HTTP-Protokolls, die Leistungseinbußen, die sonst durch die Verwendung von SSL/TLS entstehen, größtenteils oder vollständig ausgleichen kann. NGINX unterstützt HTTP/2 und Sie können HTTP/2 zusammen mit SSL/TLS beenden, wodurch wiederum keine Änderungen an den Node.js-Anwendungsservern erforderlich sind.

Zu den Implementierungsschritten, die Sie durchführen müssen, gehören das Aktualisieren der URL in der Node.js-Konfigurationsdatei, das Herstellen und Optimieren sicherer Verbindungen in Ihrer NGINX-Konfiguration und die Verwendung von SPDY oder HTTP/2, falls gewünscht. Durch das Hinzufügen der HTTP/2-Unterstützung kommunizieren Browserversionen, die HTTP/2 unterstützen, über das neue Protokoll mit Ihrer Anwendung; ältere Browserversionen verwenden weiterhin HTTP/1.x.

Der folgende Konfigurationscode ist für ein Ghost-Blog mit SPDY, wie hier beschrieben. Es enthält erweiterte Funktionen wie OCSP-Stapling. Hinweise zur Verwendung von NGINX für die SSL-Terminierung, einschließlich der OCSP-Stapling-Option, finden Sie hier . Einen allgemeinen Überblick über dieselben Themen finden Sie hier .

Sie müssen nur geringfügige Änderungen vornehmen, um Ihre Node.js-Anwendung zu konfigurieren und von SPDY auf HTTP/2 zu aktualisieren, jetzt oder wenn der SPDY-Support Anfang 2016 eingestellt wird.

Server { Servername domain.com;
Listen 443 SSL SPDY;
SPDY_Headers_Comp 6;
SPDY_Keepalive_Timeout 300;
Keepalive_Timeout 300;
SSL-Zertifikatschlüssel /etc/nginx/ssl/domain.key;
SSL-Zertifikat /etc/nginx/ssl/domain.crt;
SSL-Sitzungscache gemeinsam genutzt: SSL: 10 m; 
SSL-Sitzungstimeout 24 h; 
SSL-Puffergröße 1400; 
SSL-Stapling ein;
SSL-Stapling_Verify ein;
SSL-vertrauenswürdiges_Zertifikat /etc/nginx/ssl/trust.crt;
Resolver 8.8.8.8 8.8.4.4 gültig=300 s;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
add_header X-Cache $upstream_cache_status;

Standort / {
proxy_cache STATIC;
proxy_cache_valid 200 30 m;
proxy_cache_valid 404 1 m;
proxy_pass http://ghost_upstream;
proxy_ignore_headers X-Accel-Expires Läuft ab Cache-Control;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_hide_header X-powered-by;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
läuft in 10 Minuten ab;
}

location /content/images {
alias /path/to/ghost/content/images;
access_log off;
läuft maximal ab;
}

location /assets {
alias /path/to/ghost/themes/uno-master/assets;
access_log off;
läuft maximal ab;
}

location /public {
alias /path/to/ghost/built/public;
access_log off;
läuft maximal ab;
}

location /ghost/scripts {
alias /path/to/ghost/core/built/scripts;
access_log off;
läuft maximal ab;
}

Standort ~ ^/(?:ghost|signout) { 
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control „kein Cache, privat, kein Speicher,
muss erneut validiert werden, max-stale=0, Post-Check=0, Pre-Check=0“;
proxy_set_header X-Forwarded-Proto https;
}
}

Abschluss

Dieser Blogbeitrag beschreibt einige der wichtigsten Leistungsverbesserungen, die Sie in Ihren Node.js-Anwendungen vornehmen können. Der Schwerpunkt liegt auf der Ergänzung von NGINX zu Ihrem Anwendungsmix neben Node.js – durch die Verwendung von NGINX als Reverse-Proxy-Server, zum Zwischenspeichern statischer Dateien, zum Lastenausgleich, zum Proxying von WebSocket-Verbindungen und zum Beenden der Protokolle SSL/TLS und HTTP/2.

Die Kombination aus NGINX und Node.js wird allgemein als Möglichkeit anerkannt, neue Microservices-freundliche Anwendungen zu erstellen oder vorhandenen SOA-basierten Anwendungen, die Java oder Microsoft .NET verwenden, Flexibilität und Leistungsfähigkeit zu verleihen. Dieser Beitrag hilft Ihnen, Ihre Node.js-Anwendungen zu optimieren und, wenn Sie möchten, die Partnerschaft zwischen Node.js und NGINX zum Leben zu erwecken.


„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."