Warum sollte ich einen Reverse-Proxy verwenden, wenn Knoten.js ist produktionsbereit?

Thomas Hunter II
Thomas Hunter II

Folgen Sie

28. März 2019 · 9 min Lesezeit

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 an
ex.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.orgapi2 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:

Benchmark-Ergebnisse

Im node-cluster Benchmark verwenden wir 2 Arbeiter. Dies bedeutet, dass es 3 Knoten gibt.js-Prozesse laufen: 1 Master und 2 Worker. Im nginx-cluster-node Benchmark haben wir 2 Knoten.js-Prozesse laufen. Jeder Nginx-Test hat einen einzelnen Nginx-Master und einen einzelnen Nginx-Worker-Prozess. Benchmarks beinhalten das Lesen einer Datei von der Festplatte und weder Nginx noch Node.js wurden so konfiguriert, dass die Datei im Speicher zwischengespeichert wird.

Verwenden von Nginx zum Ausführen der SSL-Terminierung für den Knoten.dies führt zu einer Durchsatzsteigerung von ~ 16% (749 U / min auf 865 U / min). Die Verwendung von Nginx zur Durchführung der GZIP-Komprimierung führt zu einer Durchsatzsteigerung von ~ 50% (5.047 rps auf 7.590rps). Die Verwendung von Nginx zum Verwalten eines Clusters von Prozessen führte zu einer Leistungseinbuße von ~ -1% (8.006 rps bis 7.908rps), wahrscheinlich aufgrund des Overheads beim Übergeben einer zusätzlichen Anforderung über das Loopback-Netzwerkgerät.

Im Wesentlichen die Speichernutzung eines einzelnen Knotens.der js-Prozess beträgt ~ 600 MB, während die Speichernutzung eines Nginx-Prozesses bei ~ 50 MB liegt. Diese können ein wenig schwanken, je nachdem, welche Funktionen verwendet werden, z. B. Knoten.js verwendet zusätzliche ~ 13 MB, wenn die SSL-Terminierung ausgeführt wird, und Nginx verwendet zusätzliche ~ 4 MB, wenn es als Reverse-Proxy zum Bereitstellen statischer Inhalte aus dem Dateisystem verwendet wird. Eine interessante Sache zu beachten ist, dass Nginx während seiner gesamten Lebensdauer eine konsistente Menge an Speicher verwendet. Allerdings Knoten.js schwankt ständig aufgrund der müllsammelnden Natur von JavaScript.

Hier sind die Versionen der Software, die bei der Durchführung dieses Benchmarks verwendet wurden:

  • Nginx: 1.14.2
  • Node.js: 10.15.3
  • Php: 3.0.8

Die Tests wurden auf einem Computer mit 16 GB Arbeitsspeicher, einem i7-7500U CPU 4x2.70GHz und einem Linux-Kernel 4.19.10 durchgeführt. Alle notwendigen Dateien, die erforderlich sind, um die obigen Benchmarks neu zu erstellen, sind hier verfügbar:
IntrinsicLabs/nodejs-reverse-proxy-benchmarks.

Vereinfachter Anwendungscode

Benchmarks sind nett und alle, aber meiner Meinung nach die größten Vorteile der Auslagerung von Arbeit von einem Knoten.js Anwendung auf einen Reverse-Proxy ist, dass der Code Einfachheit. Wir können die Anzahl der Zeilen potenziell fehlerhaften imperativen Anwendungscodes reduzieren und gegen deklarative Konfiguration austauschen. Ein allgemeines Gefühl unter Entwicklern ist, dass sie mehr Vertrauen in Code haben, der von einem externen Team von Ingenieuren — wie Nginx — geschrieben wurde, als in Code, der von ihnen selbst geschrieben wurde.

Anstatt die gzip-Komprimierungs-Middleware zu installieren und zu verwalten und sie über verschiedene Knoten hinweg auf dem neuesten Stand zu halten.bei Projekten können wir es stattdessen an einem einzigen Ort konfigurieren. Anstatt SSL-Zertifikate zu versenden oder herunterzuladen und sie entweder erneut zu erwerben oder Anwendungsprozesse neu zu starten, können wir stattdessen vorhandene Zertifikatverwaltungstools verwenden. Anstatt unserer Anwendung Bedingungen hinzuzufügen, um zu überprüfen, ob ein Prozess ein Master oder Worker ist, können wir dies auf ein anderes Tool auslagern.Ein Reverse Proxy ermöglicht es unserer Anwendung, sich auf die Geschäftslogik zu konzentrieren und Protokolle und Prozessmanagement zu vergessen.



Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.