Die Leistungsfähigkeit und Flexibilität von JavaScript für jede Anfrage mit dem NGINX JavaScript-Modul nutzen

NGINX | 23. April 2021

Redaktion – Der Blogbeitrag mit dem Titel „Einführung in das NGINX JavaScript-Modul“ verweist auf diese Seite. Der Beitrag wurde aktualisiert und enthält nun die Direktiven und Funktionen des NGINX JavaScript-Moduls, die seit April 2021 unterstützt werden.

Das NGINX-JavaScript-Modul (njs) wurde mit NGINX Open Source 1.11.10 und NGINX Plus R12. allgemein als stabiles Modul verfügbar. [Das Modul hieß ursprünglich nginScript; dieser Name findet sich daher in einigen älteren Beiträgen.] Seit der Einführung von NGINX JavaScript im September 2015 haben wir kontinuierlich daran gearbeitet und die im stabilen Modul enthaltenen Funktionen und Sprachunterstützung hinzugefügt.

NGINX JavaScript ist eine einzigartige JavaScript-Implementierung für NGINX und NGINX Plus, die speziell für serverseitige Anwendungsfälle und die Verarbeitung einzelner Anfragen entwickelt wurde. Sie erweitert die NGINX-Konfigurationssyntax um JavaScript-Code und ermöglicht so die Umsetzung anspruchsvoller Konfigurationslösungen.

Die Einsatzmöglichkeiten sind vielfältig, insbesondere da das NGINX JavaScript-Modul sowohl für HTTP- als auch für TCP/UDP-Protokolle verfügbar ist. Beispiele für den Einsatz von NGINX JavaScript sind:

Bevor wir NGINX JavaScript näher erläutern, wollen wir zunächst zwei weitverbreitete Missverständnisse ausräumen.

NGINX JavaScript ist nicht Lua

Die NGINX-Community hat im Laufe der Jahre mehrere programmierbare Erweiterungen entwickelt. Zum Zeitpunkt der Erstellung dieses Artikels ist Lua die beliebteste davon. Es ist als Modul für NGINX sowie als unterstütztes, vorkompiliertes dynamisches Drittanbietermodul für NGINX Plus verfügbar. Das Lua-Modul und die Zusatzbibliotheken bieten eine tiefgreifende Integration in den NGINX-Kern sowie einen umfangreichen Funktionsumfang, darunter einen Treiber für Redis.

Lua ist eine leistungsstarke Skriptsprache. Allerdings ist sie nach wie vor relativ wenig verbreitet und gehört üblicherweise nicht zum Kompetenzrepertoire von Frontend-Entwicklern oder DevOps-Ingenieuren.

NGINX JavaScript soll Lua nicht ersetzen, und es wird noch einige Zeit dauern, bis NGINX JavaScript einen vergleichbaren Funktionsumfang bietet. Ziel von NGINX JavaScript ist es, durch den Einsatz einer weitverbreiteten Programmiersprache einer möglichst großen Community Lösungen für die programmatische Konfiguration bereitzustellen.

NGINX JavaScript ist nicht Node.js

NGINX JavaScript zielt nicht darauf ab, NGINX oder NGINX Plus in einen Anwendungsserver zu verwandeln. Vereinfacht gesagt ähneln die Anwendungsfälle für NGINX JavaScript denen von Middleware, da der JavaScript-Code zwischen dem Client und dem Inhalt ausgeführt wird. Technisch gesehen haben Node.js und die Kombination aus NGINX JavaScript und NGINX oder NGINX Plus nur zwei Dinge gemeinsam – eine ereignisgesteuerte Architektur und die Programmiersprache JavaScript – darüber hinaus enden die Gemeinsamkeiten.

Node.js verwendet die Google-V8-JavaScript-Engine, während NGINX JavaScript eine speziell für NGINX und NGINX Plus entwickelte Implementierung der ECMAScript-Standards ist. Node.js hält eine persistente virtuelle JavaScript-Maschine (VM) im Arbeitsspeicher vor und führt zur Speicherverwaltung regelmäßig eine Garbage Collection durch. NGINX JavaScript hingegen initialisiert für jede Anfrage eine neue JavaScript-VM sowie den erforderlichen Arbeitsspeicher und gibt diesen nach Abschluss der Anfrage wieder frei.

JavaScript als serverseitige Sprache

Wie bereits erwähnt, ist NGINX JavaScript eine speziell entwickelte Implementierung der Programmiersprache JavaScript. Alle anderen vorhandenen JavaScript-Laufzeitumgebungen sind für die Ausführung in einem Webbrowser konzipiert. Die Ausführung von clientseitigem Code unterscheidet sich in vielerlei Hinsicht von der Ausführung von serverseitigem Code – von der Verfügbarkeit von Systemressourcen bis hin zur möglichen Anzahl gleichzeitig ausgeführter Laufzeitinstanzen.

Wir haben uns entschieden, eine eigene JavaScript-Laufzeitumgebung zu implementieren, um die Anforderungen an die serverseitige Codeausführung zu erfüllen und sie nahtlos in die Architektur von NGINX zur Verarbeitung von Anfragen zu integrieren. Unsere Designprinzipien für NGINX JavaScript lauten:

  • Die Laufzeitumgebung wird mit der Anfrage erstellt und anschließend wieder beendetDas NGINX JavaScript-Modul führt Bytecode in einem einzelnen Thread aus und ist auf eine schnelle Initialisierung und Freigabe ausgelegt. Die Laufzeitumgebung wird für jede Anfrage neu initialisiert. Der Start erfolgt äußerst schnell, da weder ein komplexer Zustand noch Hilfsfunktionen initialisiert werden müssen. Während der Ausführung wird Speicher in Pools gesammelt und nach Abschluss durch Freigabe der Pools wieder freigegeben. Dank dieses Speicherverwaltungsschemas müssen einzelne Objekte weder nachverfolgt noch freigegeben werden, und auch eine automatische Speicherbereinigung ist nicht erforderlich.
  • Nicht blockierende CodeausführungDas ereignisgesteuerte Modell von NGINX und NGINX Plus plant die Ausführung der einzelnen NGINX JavaScript-Laufzeitumgebungen. Wenn eine NGINX JavaScript-Regel einen blockierenden Vorgang ausführt (z. B. Netzwerkdaten liest oder eine externe Unteranfrage sendet), unterbrechen NGINX und NGINX Plus transparent die Ausführung der zugehörigen NGINX JavaScript-VM und planen sie nach Abschluss des Ereignisses erneut ein. Das bedeutet, dass Sie Regeln auf einfache, lineare Weise schreiben können und NGINX und NGINX Plus deren Ausführung ohne interne Blockierung planen.
  • Nur die Sprachfunktionen implementieren, die wir benötigenDie Spezifikationen für JavaScript werden durch die ECMAScript-Standards definiert. NGINX JavaScript folgt ECMAScript 5.1 mit einigen Funktionen aus ECMAScript 6 für mathematische Berechnungen. Durch die Implementierung einer eigenen JavaScript-Laufzeitumgebung können wir Sprachfunktionen für serverseitige Anwendungsfälle priorisieren und nicht benötigte Funktionen außer Acht lassen. Wir führen eine Liste der derzeit unterstützten Sprachelemente.
  • Enge Integration in die Phasen der AnforderungsverarbeitungNGINX und NGINX Plus verarbeiten Anforderungen in verschiedenen Phasen. Konfigurationsanweisungen werden in der Regel in einer bestimmten Phase ausgeführt, und native NGINX-Module nutzen häufig die Möglichkeit, eine Anforderung in einer bestimmten Phase zu prüfen oder zu ändern. NGINX JavaScript macht einige der Verarbeitungsphasen über Konfigurationsanweisungen zugänglich, sodass sich steuern lässt, wann der JavaScript-Code ausgeführt wird. Diese Integration in die Konfigurationssyntax verbindet die Leistungsfähigkeit und Flexibilität nativer NGINX-Module mit der Einfachheit von JavaScript-Code. Die folgende Tabelle zeigt, welche Verarbeitungsphasen zum Zeitpunkt der Erstellung über NGINX JavaScript zugänglich sind und welche Konfigurationsanweisungen den Zugriff darauf ermöglichen.
VerarbeitungsphaseHTTP-ModulStream-Modul
Access – Authentifizierung und Zugriffskontrolleauth_request und js_contentjs_access
Pre-read – Nutzdaten lesen/schreibenk. A.js_preread
Filter – Antwort während des Proxy-Vorgangs lesen/schreibenjs_body_filter
js_header_filter
js_filter
Content – Antwort an den Client sendenjs_contentk. A.
Log / Variables – Bei Bedarf ausgewertetjs_setjs_set

Erste Schritte mit NGINX JavaScript – ein praxisnahes Beispiel

NGINX JavaScript ist als Modul implementiert, das Sie in eine NGINX Open Source-Binärdatei kompilieren oder dynamisch in NGINX bzw. NGINX Plus laden können. Anleitung zum Aktivieren von NGINX JavaScript mit NGINX und NGINX Plus finden Sie am Ende dieses Artikels.

In diesem Beispiel verwenden wir NGINX oder NGINX Plus als einfachen Reverse-Proxy und erstellen mit NGINX JavaScript Zugriffsprotokolleinträge in einem speziellen Format, das:

  • Enthält die vom Client gesendeten Anfrage-Header
  • Enthält die vom Backend zurückgegebenen Antwort-Header
  • Verwendet Schlüssel-Wert-Paare für die effiziente Aufnahme in und Suche mit Protokollverarbeitungstools wie dem ELK Stack (jetzt Elastic Stack genannt), Graylog und Splunk

Die NGINX-Konfiguration für dieses Beispiel ist äußerst einfach.

Codebeispiel wird geladen…

Wie Sie sehen, ist der NGINX-JavaScript-Code nicht direkt in die Konfigurationssyntax eingebettet. Stattdessen verwenden wir die js_import-Direktive, um die Datei anzugeben, die unseren gesamten JavaScript-Code enthält. Die js_set-Direktive definiert eine neue NGINX-Variable, $access_log_headers, sowie die JavaScript-Funktion, die sie mit einem Wert befüllt. Die log_format-Direktive definiert ein neues Format namens kvpairs, das jede Protokollzeile mit dem Wert von $access_log_headers schreibt.

Der server-Block definiert einen einfachen HTTP-Reverse-Proxy, der alle Anfragen an https://www.example.com weiterleitet. Die access_log-Direktive legt fest, dass alle Anfragen im kvpairs-Format protokolliert werden.

Sehen wir uns nun den JavaScript-Code an, der einen Protokolleintrag vorbereitet.

Codebeispiel wird geladen…

Der Rückgabewert der Funktion kvAccess – ein Protokolleintrag – wird an die Konfigurationsanweisung js_set in rawheader_logging.conf übergeben. Beachten Sie, dass NGINX-Variablen bei Bedarf ausgewertet werden. Das bedeutet wiederum, dass die durch js_set definierte JavaScript-Funktion ausgeführt wird, sobald der Wert der Variablen benötigt wird. In diesem Beispiel wird $access_log_headers in der Anweisung log_format verwendet, sodass kvAccess() zum Zeitpunkt der Protokollierung ausgeführt wird. Variablen, die als Teil von map- oder rewrite-Anweisungen verwendet werden (in diesem Beispiel nicht dargestellt), lösen die entsprechende JavaScript-Ausführung in einer früheren Verarbeitungsphase aus.

Wir können diese durch NGINX JavaScript erweiterte Protokollierungslösung in Aktion sehen, indem wir eine Anfrage über unseren Reverse-Proxy leiten und den daraus resultierenden Protokolldateieintrag betrachten. Dieser enthält Anfrage-Header mit dem Präfix „in.“ und Antwort-Header mit dem Präfix „out.“.

$ curl http://127.0.0.1/$ tail --lines=1 /var/log/nginx/access_headers.log2021-04-23T10:08:15+00:00 client=172.17.0.1 method=GET uri=/index.html status=200 in.Host=localhost:55081 in.User-Agent=curl/7.64.1 in.Accept=*/* out.Content-Type=text/html out.Content-Length=612 out.ETag=x22606339ef-264x22 out.Accept-Ranges=bytes

Ein Großteil des Nutzens von NGINX JavaScript ergibt sich aus dem Zugriff auf interne Funktionen von NGINX. In diesem Beispiel werden mehrere Eigenschaften des Anfrageobjekts (r) verwendet. Das NGINX JavaScript-Stream-Modul (für TCP- und UDP-Anwendungen) verwendet ein Sitzungsobjekt (s) mit eigenen Eigenschaften. Weitere Beispiele für NGINX JavaScript-Lösungen für HTTP und TCP/UDP finden Sie unter Anwendungsfälle für das NGINX JavaScript-Modul.

Wir würden gerne erfahren, welche Anwendungsfälle Sie für NGINX JavaScript entwickeln – berichten Sie uns davon im Kommentarbereich unten.

Anwendungsfälle für das NGINX-JavaScript-Modul

In diesen Blogbeiträgen erfahren Sie mehr über weitere HTTP- und TCP/UDP-Anwendungsfälle für das NGINX JavaScript-Modul:

[ngx_snippet name=’njs-enable-instructions’]


Teilen
Schlagwörter: F5 NGINX, 2021, Tech

Über den Autor

Liam Crilly
Liam CrillySenior Director, Produktmanagement

Weitere Blogbeiträge von Liam Crilly

Ähnliche Blogbeiträge

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
NGINX | 23.08.2022

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln

Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
NGINX | 08.09.2021

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen

Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
NGINX | 16.08.2021

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet

Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
NGINX | 12.12.2018

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77

Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.

Ankündigung von NGINX Plus R16
NGINX | 05.09.2018

Ankündigung von NGINX Plus R16

NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
NGINX | 13.10.2016

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing

Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.