Warum sollte ich einen Reverse-Proxy verwenden, wenn Knoten.js ist produktionsbereit?
Das Jahr war 2012. PHP und Ruby on Rails regierten als oberste serverseitige Technologien zum Rendern von Webanwendungen. Aber, Ein mutiger neuer Anwärter eroberte die Community im Sturm – eine, die es schaffte, 1M gleichzeitige Verbindungen zu handhaben. Diese Technologie war nichts anderes als Knoten.js und hat seitdem stetig an Popularität gewonnen.
Im Gegensatz zu den meisten konkurrierenden Technologien der Zeit, Knoten.js kam mit einem eingebauten Webserver. Mit diesem Server konnten Entwickler eine Vielzahl von Konfigurationsdateien wie php.ini
und eine hierarchische Sammlung von.htaccess
Dateien umgehen. Ein integrierter Webserver bot auch andere Annehmlichkeiten, wie die Möglichkeit, Dateien beim Hochladen zu verarbeiten, und die einfache Implementierung von WebSockets.
Jeden Tag Knoten.js-basierte Webanwendungen verarbeiten gerne Milliarden von Anfragen. Die meisten der größten Unternehmen der Welt werden in irgendeiner Weise von Node angetrieben.js. Um diesen Knoten zu sagen.js ist Produktionsreif ist sicherlich eine
Untertreibung. Es gibt jedoch einen Ratschlag, der sich seitdem bewahrheitet hat.js Anfang: Man sollte einen Knoten nicht direkt verfügbar machen.js-Prozess auf das Web und sollte es stattdessen hinter einem Reverse-Proxy verstecken. Bevor wir uns jedoch die Gründe ansehen, warum wir einen Reverse-Proxy verwenden möchten, schauen wir uns zunächst an, was einer ist.Ein Reverse-Proxy ist im Grunde eine spezielle Art von Webserver, der Anfragen empfängt, sie an einen anderen HTTP-Server weiterleitet, eine Antwort empfängt und die Antwort an den ursprünglichen Anforderer weiterleitet.
Ein Reverse-Proxy sendet jedoch normalerweise nicht die genaue Anfrage. In der Regel wird die Anforderung auf irgendeine Weise geändert. Wenn der Reverse-Proxy beispielsweise unter www.example.org:80
lebt und die Anforderung anex.example.org:8080
weiterleitet, wird er wahrscheinlich den ursprünglichen Host
Header umschreiben, um dem des Ziels zu entsprechen. Es kann die Anforderung auch auf andere Weise ändern, z. B. eine fehlerhafte Anforderung bereinigen oder zwischen Protokollen übersetzen.
Sobald der Reverse-Proxy eine Antwort erhält, kann er diese Antwort auf irgendeine Weise übersetzen. Auch hier besteht ein üblicher Ansatz darin, den Header Host
so zu ändern, dass er mit der ursprünglichen Anforderung übereinstimmt. Der Text der Anfragen kann ebenfalls geändert werden. Eine übliche Modifikation besteht darin, die Antwort mit gzip zu komprimieren. Eine weitere häufige Änderung besteht darin, die HTTPS-Unterstützung zu aktivieren, wenn der zugrunde liegende Dienst nur HTTP spricht.
Reverse-Proxys können auch eingehende Anfragen an mehrere Backend-Instanzen senden. Wenn ein Dienst unter api.example.org
verfügbar gemacht wird, kann ein Reverse-Proxy Anforderungen an api1.internal.example.org
api2
usw. weiterleiten.
Es gibt viele verschiedene Reverse-Proxies. Zwei der beliebtesten sind Nginx und HAProxy. Beide Tools sind in der Lage, gzip-Komprimierung durchzuführen und HTTPS-Unterstützung hinzuzufügen, und sie sind auch auf andere Bereiche spezialisiert. Nginx ist die populärere der beiden Möglichkeiten, und hat auch einige andere
vorteilhafte Funktionen wie die Fähigkeit, statische Dateien aus einem Dateisystem zu dienen, so werden wir es als Beispiel in diesem Artikel verwenden.
Nun, da wir wissen, was ein Reverse-Proxy ist, können wir nun untersuchen, warum wir einen mit Node verwenden möchten.js.
Warum sollte ich einen Reverse Proxy verwenden?
Die SSL-Terminierung ist einer der beliebtesten Gründe für die Verwendung eines Reverse-Proxys. Das Ändern des Protokolls einer Anwendung von http
in https
erfordert etwas mehr Arbeit als das Anhängen einer s
. Knoten.js selbst kann die erforderliche Ver- und Entschlüsselung für https
durchführen und kann so konfiguriert werden, dass die erforderlichen Zertifikatsdateien gelesen werden.
Das Konfigurieren des Protokolls, das für die Kommunikation mit unserer Anwendung verwendet wird, und das Verwalten immer ablaufender SSL-Zertifikate ist jedoch nicht wirklich etwas, worüber sich unsere Anwendung Gedanken machen muss. Das Einchecken von Zertifikaten in eine Codebasis wäre nicht nur mühsam, sondern auch ein Sicherheitsrisiko. Der Erwerb von Zertifikaten von einer zentralen Stelle beim Start der Anwendung birgt auch Risiken.
Aus diesem Grund ist es besser, die SSL-Terminierung außerhalb der Anwendung durchzuführen, normalerweise innerhalb eines Reverse-Proxys. Dank Technologien wie certbot
von Let’s Encrypt ist das Verwalten von Zertifikaten mit Nginx so einfach wie das Einrichten eines Cron-Jobs. Ein solcher Job kann automatisch neue Zertifikate installieren und den Nginx-Prozess dynamisch neu konfigurieren. Dies ist ein viel weniger störender Prozess als beispielsweise das Neustarten jedes Knotens.js Anwendungsinstanz.
Wenn ein Reverse-Proxy die SSL-Terminierung durchführen kann, bedeutet dies auch, dass nur Code, der von den Reverse-Proxy-Autoren geschrieben wurde, Zugriff auf Ihr privates SSL-Zertifikat hat. Wenn jedoch Ihr Knoten.wenn die Anwendung SSL verarbeitet, hat jedes einzelne von Ihrer Anwendung verwendete Drittanbietermodul — auch potenziell schädliche Module — Zugriff auf Ihr privates SSL-Zertifikat.
gzip-Komprimierung
Die gzip-Komprimierung ist eine weitere Funktion, die Sie von der Anwendung auf einen Reverse-Proxy auslagern sollten. gzip-Komprimierungsrichtlinien werden am besten auf Organisationsebene festgelegt, anstatt sie für jede Anwendung angeben und konfigurieren zu müssen.
Es ist am besten, eine Logik zu verwenden, wenn Sie entscheiden, was Sie gzipen möchten. Zum Beispiel sind Dateien, die sehr klein sind, vielleicht kleiner als 1kb, wahrscheinlich nicht wert, komprimiert zu werden, da die gzip-komprimierte Version manchmal größer sein kann, oder der CPU-Overhead, wenn der Client die Datei dekomprimiert, ist es möglicherweise nicht wert. Wenn Sie mit Binärdaten arbeiten, profitieren sie je nach Format möglicherweise nicht von der Komprimierung. gzip ist auch etwas, das nicht einfach aktiviert oder deaktiviert werden kann, es erfordert die Prüfung der eingehenden Accept-Encoding
Header für kompatible Komprimierungsalgorithmen.
Clustering
JavaScript ist eine Single-Threaded-Sprache und dementsprechend Node.js war traditionell eine Single-Threaded-Serverplattform (obwohl die derzeit experimentelle Worker-Thread-Unterstützung in Node verfügbar ist.js v10 zielt darauf ab, dies zu ändern). Dies bedeutet, dass Sie so viel Durchsatz von einem Knoten erhalten.js-Anwendung wie möglich erfordert etwa die gleiche Anzahl von Instanzen ausgeführt werden, da es CPU-Kerne.
Knoten.js kommt mit einem eingebauten cluster
Modul, das genau das kann. Eingehende HTTP-Anforderungen werden an einen Masterprozess gesendet und dann an Cluster-Worker gesendet.
Die dynamische Skalierung von Cluster-Workern würde jedoch einige Anstrengungen erfordern. Es gibt auch in der Regel zusätzlichen Overhead beim Ausführen eines zusätzlichen Knotens.js-Prozess als Dispatching-Master-Prozess. Auch das Skalieren von Prozessen über verschiedene Maschinen hinweg ist etwas, was cluster
nicht kann.
Aus diesen Gründen ist es manchmal besser, einen Reverse-Proxy zu verwenden, um Anforderungen an den laufenden Knoten zu senden.js-Prozesse. Solche Reverse-Proxys können dynamisch konfiguriert werden, um auf neue Anwendungsprozesse zu verweisen, sobald sie eintreffen. Wirklich, eine Anwendung sollte sich nur darum kümmern, ihre eigene Arbeit zu erledigen, sie sollte sich nicht darum kümmern, mehrere Kopien zu verwalten und Anforderungen zu senden.
Enterprise Routing
Wenn es um massive Webanwendungen geht, wie sie von Multi-Team-Unternehmen erstellt werden, ist es sehr nützlich, einen Reverse-Proxy zu haben, um zu bestimmen, wohin Anfragen weitergeleitet werden sollen. Beispielsweise können Anforderungen an example.org/search/*
an die interne Suchanwendung weitergeleitet werden, während andere Anforderungen an example.org/profile/*
an die interne Profilanwendung gesendet werden können.
Ein solches Tool ermöglicht andere leistungsstarke Funktionen wie Sticky Sessions, Blue / Green-Bereitstellungen, A / B-Tests usw. Ich habe persönlich in einer Codebasis gearbeitet, in der eine solche Logik innerhalb der Anwendung ausgeführt wurde, und dieser Ansatz machte die Wartung der Anwendung ziemlich schwierig.
Leistungsvorteile
Knoten.js ist sehr formbar. Es kann statische Assets aus einem Dateisystem bereitstellen, Gzip-Komprimierung mit HTTP-Antworten durchführen, verfügt über integrierte Unterstützung für HTTPS und viele andere Funktionen. Es hat sogar die Möglichkeit, mehrere Instanzen einer Anwendung auszuführen und über das Modul cluster
eine eigene Anforderungsverteilung durchzuführen.Und doch ist es letztendlich in unserem besten Interesse, einen Reverse-Proxy diese Operationen für uns erledigen zu lassen, anstatt unseren Knoten zu haben.js-Anwendung tun es. Abgesehen von den oben aufgeführten Gründen ein weiterer Grund, diese Vorgänge außerhalb des Knotens ausführen zu wollen.das liegt an der Effizienz.
SSL-Verschlüsselung und GZIP-Komprimierung sind zwei stark CPU-gebundene Vorgänge. Dedizierte Reverse-Proxy-Tools wie Nginx und HAProxy führen diese Vorgänge normalerweise schneller aus als Node.js. Wenn ein Webserver wie Nginx statischen Inhalt von der Festplatte liest, ist dies schneller als der Knoten.js auch. Sogar Clustering kann manchmal effizienter sein, da ein Reverse-Proxy wie Nginx weniger Speicher und CPU benötigt als der eines zusätzlichen Knotens.js-Prozess.
Aber nehmen Sie unser Wort nicht dafür. Lassen Sie uns einige Benchmarks ausführen!
Der folgende Lasttest wurde mit siege
durchgeführt. Wir haben den Befehl mit einem Parallelitätswert von 10 ausgeführt (10 gleichzeitige Benutzer, die eine Anforderung stellen), und der Befehl wurde ausgeführt, bis 20.000 Iterationen ausgeführt wurden (für insgesamt 200.000 Anforderungen).
Um den Speicher zu überprüfen, führen wir den Befehl pmap <pid> | grep total
einige Male während der gesamten Lebensdauer des Benchmarks aus und mitteln dann die Ergebnisse. Wenn Nginx mit einem einzelnen Worker-Thread ausgeführt wird, werden zwei Instanzen ausgeführt, von denen eine der Master und die andere der Worker ist. Wir summieren dann die beiden Werte. Beim Ausführen eines Knotens.in einem Cluster von 2 gibt es 3 Prozesse, von denen einer der Master und die anderen beiden Worker sind. Die Spalte approx memory in der folgenden Tabelle ist eine Gesamtsumme jedes Nginx und Knotens.js-Prozess für den gegebenen Test.
Hier sind die Ergebnisse des Benchmarks: