API-Anfragen mit NGINX Plus und dem NGINX-JavaScript-Modul bündeln

NGINX | 24. Mai 2018

Die mit NGINX JavaScript-Modul veröffentlichte Version von NGINX Plus R15 kann nun Unteranfragen ausführen, das heißt, Anfragen können im JavaScript-Code initiiert werden. Dadurch lassen sich völlig neue Anwendungsfälle abdecken.

Einer dieser Anwendungsfälle ist die Bündelung von API-Anfragen, sodass eine einzelne API-Anfrage eines Clients in mehrere API-Anfragen an verschiedene Backend-Server aufgeteilt und deren Antworten zu einer einzigen Antwort an den Client zusammengeführt werden können. In diesem Blog dient eine E-Commerce-Website als Beispiel: Wenn der Client Informationen zu einem bestimmten Produkt anfordert, werden Unteranfragen an drei Backend-Dienste gestellt: Katalog, Lagerbestand und Kundenrezensionen.

Dieser Beitrag baut auf dem Beispiel für Unteranfragen in der Ankündigung zu NGINX Plus R15 auf. Darin wird gezeigt, wie sich mit Unteranfragen dieselbe Anfrage an zwei Backend-Server senden und nur die erste Antwort an den Client zurückgeben lässt.

[Redaktion – Dieser Beitrag ist einer von mehreren, die sich mit Anwendungsfällen für das NGINX-JavaScript-Modul befassen. Eine vollständige Liste finden Sie unter „Anwendungsfälle für das NGINX-JavaScript-Modul“.

Der Beitrag wurde aktualisiert und verwendet nun die js_import-Direktive, welche die js_include-Direktive ab NGINX Plus R23 ersetzt. Weitere Informationen finden Sie in der Referenzdokumentation zum NGINX-JavaScript-Modul – im Abschnitt Beispielkonfiguration wird die korrekte Syntax für NGINX-Konfigurations- und JavaScript-Dateien gezeigt.]

Einführung

Ziel dieses Beitrags ist es, einfache und verständliche, funktionsfähige Beispiele für die Bündelung von API-Anfragen bereitzustellen. Die Beispiele erfüllen alle folgenden Anforderungen:

  • Für alle Anfragen wird die HTTP-Methode „GET“ verwendet.
  • Alle Antworten werden im JSON-Format zurückgegeben.
  • Es werden zwei Arten von API-Anfragen unterstützt. Beachten Sie, dass bei beiden Arten zusätzliche Argumente in der Abfragezeichenfolge enthalten sein können.
    • Das Argument für das API-Programm ist das letzte Element des URI. Dies bezeichnen wir als Anfragestil mit abschließendem Element. In unserem Beispiel löst eine Clientanfrage an /batch-api/product/14286 Anfragen an /myapi/catalog/14286, /myapi/inventory/14286 und /myapi/review/14286 aus.
    • Das Argument wird in der Abfragezeichenfolge des URI angegeben. Wir bezeichnen dies als Abfragezeichenfolgen-Anforderungsstil. Im Beispiel löst eine Anfrage an /batch-api2/product?item=14286 Anfragen an /myapi/catalog.php?item=14286, /myapi/inventory.php?item=14286 und /myapi/review.php?item=14286 aus.
  • Die durch eine Clientanfrage ausgelöste Gruppe von Unteranfragen lässt sich dynamisch konfigurieren. Das bedeutet, dass wir sie ändern können, ohne die NGINX Plus-Konfiguration manuell bearbeiten und neu laden zu müssen.
  • Die API-Anfragen an die Backend-Server sind voneinander unabhängig.

Lösungsübersicht

Neben der neuen Subrequest-Funktion von NGINX JavaScript nutzt diese Lösung den Key-Value-Speicher von NGINX Plus, sodass Konfigurationsänderungen dynamisch über die NGINX Plus API vorgenommen werden können.

Die folgenden Abbildungen veranschaulichen die beiden unterstützten Anforderungsarten.

Anfragestil für das letzte Element:

Client stellt Anfragen im Final-Element-Stil an eine API

Anfragestil mit Abfragezeichenfolge:

Client sendet Anfragen im Query-String-Stil an eine API

In beiden Beispielen muss der Client Informationen zu einem Produkt vom Katalog-, Bestands- und Bewertungsdienst abrufen. Er sendet eine Anfrage an NGINX Plus und übergibt dabei die Artikelnummer entweder als Teil des URI oder in der Abfragezeichenfolge. Anschließend werden Anfragen an die drei Dienste gesendet und deren Antworten zu einer einzigen Antwort an den Client zusammengefasst.

Damit dies mit NGINX Plus funktioniert, sind zwei Komponenten erforderlich: ein JavaScript-Programm und die NGINX Plus-Konfiguration.

Das JavaScript-Programm

Die JavaScript-Funktion batchAPI() wird für jede Clientanfrage aufgerufen. Sie ruft die durch Kommas getrennte Liste der API-URIs aus dem Schlüssel-Wert-Speicher ab, durchläuft sie, stellt für jeden Eintrag eine Unteranfrage und gibt dabei die Callback-Funktion done() zur Verarbeitung der jeweiligen Antwort an. Bei Anfragen im Stil eines abschließenden Elements wird das letzte Element des URI, das in der NGINX-Variable $uri_suffix gespeichert ist, zusammen mit allen weiteren Abfragezeichenfolgenargumenten im ursprünglichen Client-URI als Abfragezeichenfolge an jede Unteranfrage übergeben. Bei Anfragen im Abfragezeichenfolgenstil wird die Abfragezeichenfolge der Clientanfrage als Abfragezeichenfolge an jede Unteranfrage übergeben.

Die Aufrufe erfolgen in der Reihenfolge, in der sie im Schlüssel-Wert-Speicher aufgeführt sind. Da sie jedoch asynchron ausgeführt werden, können die Antworten in beliebiger Reihenfolge eintreffen. Die Antworten werden in der Reihenfolge ihres Eingangs zu einer einzigen Antwort an den Client zusammengefasst. Hier ist eine Minimalversion des JavaScript-Programms:

Codebeispiel wird geladen…

Eine Version des JavaScript-Programms mit umfassenderer Fehlerbehandlung, Protokollierung und Kommentierung ist im GitHub-Gist-Repository unter dem Namen „batch-api.js“ verfügbar.

Minimale NGINX Plus-Konfiguration

Die folgende NGINX Plus-Konfiguration implementiert die beiden oben beschriebenen Anfragestile unter Verwendung einer Gruppe von Upstream-Servern. Der Einfachheit halber wird davon ausgegangen, dass die Upstream-Server einen Aufruf der Form /myapi/service/item# (Stil mit abschließendem Element) in /myapi/service.php/?item=item# (Abfragezeichenfolgenstil) übersetzen können. Letzteres ist das „native“ URI-Format für PHP, die Sprache, in der unsere beispielhaften Katalog-, Bestands- und Bewertungsdienste implementiert sind.

Eine umfassendere NGINX Plus-Konfiguration, die die Übersetzung selbst durchführt, finden Sie weiter unten unter „Erweitern der NGINX-Konfiguration zur Übersetzung von URIs“.

Sehen wir uns die Konfigurationsdatei Abschnitt für Abschnitt an und erläutern wir, welche Funktion die einzelnen Teile haben:

  • Importieren Sie die JavaScript-Datei:

    Codebeispiel wird geladen…

  • Definieren Sie einen Schlüssel-Wert-Speicher für die Liste der API-Anfragen, bei denen das letzte Element des URI das Argument für das API-Programm angibt. Der Schlüssel verwendet die Variable $uri_prefix, um den Teil des URI vor dem letzten / zu erfassen:

    Codebeispiel wird geladen…

    Ab NGINX Plus R16 können Sie zwei zusätzliche Schlüssel-Wert-Funktionen nutzen: Anweisungen zum Einrichten der Synchronisierung für Schlüssel-Wert-Speicher finden Sie im NGINX Plus-Administratorhandbuch.
    • Legen Sie eine Ablaufzeit für die Einträge in einem Schlüssel-Wert-Speicher fest, indem Sie den Parameter timeout zur Direktive keyval_zone hinzufügen. Wenn beispielsweise jede gebündelte URI nach einem Tag ablaufen soll, fügen Sie timeout=1d hinzu.
    • Synchronisieren Sie den Schlüssel-Wert-Speicher über einen Cluster von NGINX Plus-Instanzen hinweg, indem Sie der Direktive sync den Parameter keyval_zone hinzufügen. In diesem Fall müssen Sie auch den Parameter timeout angeben.
  • Definieren Sie einen weiteren Schlüssel-Wert-Speicher für APIs, bei denen das Argument im Abfragestring angegeben wird. Hier erfasst der Schlüssel ($uri) den gesamten URI ohne den Abfragestring:

    Codebeispiel wird geladen…

  • Definieren Sie zwei Zuordnungen zur Aufteilung des URI in zwei Teile für APIs, die Anfragen akzeptieren, bei denen das Argument das letzte Element des URI ist. Die Variable $uri_prefix erfasst die URI-Elemente vor dem letzten / und $uri_suffix erfasst das letzte Element:

    Codebeispiel wird geladen…

  • Definieren Sie die Upstream-Gruppe der API-Server (hier werden sie zusammen mit NGINX Plus auf localhost ausgeführt):

    Codebeispiel wird geladen…

  • Definieren Sie den virtuellen Server, der Clientanfragen und Unteranfragen verarbeitet:

    Codebeispiel wird geladen…

  • Definieren Sie einen location-Block zur Verarbeitung von Clientanfragen, die den Stil mit abschließendem Element verwenden. Dies wird der Funktion batchAPI mitgeteilt, indem die Variable $batch_api_arg_in_uri auf on gesetzt wird:

    Codebeispiel wird geladen…

  • Definieren Sie eine Location zur Verarbeitung von Clientanfragen, die das Abfragezeichenfolgenformat verwenden. Dies wird der Funktion „batchAPI“ mitgeteilt, indem die Variable „$batch_api_arg_in_uri“ auf „off“ gesetzt wird:

    Codebeispiel wird geladen…

  • Definieren Sie den Location-Block, der die Unteranfragen verarbeitet:

    Codebeispiel wird geladen…

  • Aktivieren Sie die NGINX Plus API, damit Daten im Schlüssel-Wert-Speicher verwaltet werden können:

    Codebeispiel wird geladen…

Hier ist die vollständige Konfiguration:

Codebeispiel wird geladen…

Konfigurieren der gebündelten API-Anfragen

Wir verwenden die Schlüssel-Wert-Speicherfunktion von NGINX Plus, um eingehende Clientanfragen einer Reihe auszuführender API-Anfragen zuzuordnen. Die Konfiguration im vorherigen Abschnitt definiert separate Schlüssel-Wert-Speicher für die beiden Anfragestile:

  • Der Schlüssel-Wert-Speicher für den Stil mit abschließendem Element heißt „batch_api“, und als Schlüssel dient die Variable „$uri_prefix“, die die Elemente vor dem letzten „/“ des Anfrage-URI erfasst.
  • Der Schlüssel-Wert-Speicher für die Abfragezeichenfolgen-Variante heißt batch_api2, und als Schlüssel dient die Variable $uri, die den vollständigen Anfrage-URI ohne die Abfragezeichenfolge erfasst.

In beiden Schlüssel-Wert-Speichern ist der jedem Schlüssel zugeordnete Wert eine durch Kommas getrennte Liste von URIs, die zur Laufzeit in den Variablen $batch_api bzw. $batch_api2 verfügbar gemacht werden.

Bei Anfragen im Stil eines abschließenden Elements möchten wir eine Clientanfrage an /batch-api/product Anfragen an die drei Dienste /myapi/catalog, /myapi/inventory und /myapi/review zuordnen, sodass eine Anfrage an /batch-api/product/14286 zu Anfragen an /myapi/catalog/14286, /myapi/product/14286 und /myapi/review/14286 führt.

Um diese Zuordnungen zum Key-Value-Speicher batch_api hinzuzufügen, senden wir die folgende Anfrage an die auf dem lokalen Rechner ausgeführte NGINX Plus-Instanz:

$ curl -iX POST -d '{"/batch-api/product":"/myapi/catalog,/myapi/inventory,/myapi/review"}' http://localhost/api/3/http/keyvals/batch_api

Bei Anfragen im Query-String-Stil möchten wir eine Clientanfrage an /batch-api2/product Anfragen an die drei Dienste /myapi/catalog.php, /myapi/inventory.php und /myapi/review.php zuordnen, sodass eine Anfrage an /batch-api2/product?item=14286 zu Anfragen an /myapi/catalog?item=14286, /myapi/product?item=14286 und /myapi/review?item=14286 führt.

Um diese Zuordnungen zum Key-Value-Store batch_api2 hinzuzufügen, senden wir die folgende Anfrage:

$ curl -iX POST -d '{"/batch-api2/product":"/myapi/catalog.php,/myapi/inventory.php,/myapi/review.php"}' http://localhost/api/3/http/keyvals/batch_api2

Ausführen der Beispiele

Dieselben PHP-Seiten verarbeiten Anfragen in beiden Anfragestilen. Der Einfachheit halber gehen wir davon aus, dass die Backend-Server URIs im Final-Element-Stil (/myapi/service/item#) in URIs im Query-String-Stil (/myapi/service.php?item=item#) umwandeln können. URIs im Query-String-Stil müssen nicht umgewandelt werden, da dies das „native“ URI-Format für PHP-Programme ist.

Alle Dienste geben eine JSON-formatierte Antwort zurück, die den Dienstnamen und das Elementargument enthält. Beispielsweise führt eine Anfrage an /myapi/catalog.php?item=14286 zu folgender Antwort von catalog.php:

{"service":"Catalog","item":"14286"}

Obwohl die in diesen Beispielen verwendeten PHP-Programme den Namen des Dienstes in die Antwort aufnehmen, ist dies möglicherweise nicht bei allen Diensten der Fall. Damit die Antworten leichter den Diensten zugeordnet werden können, von denen sie stammen, nimmt das JavaScript-Programm den URI in die aggregierte Antwort auf.

Die aggregierte Antwort auf eine Anfrage an /batch-api/product/14286 sieht beispielsweise wie folgt aus (wobei die Reihenfolge der drei Teilantworten variieren kann):

[["/myapi/review/14286",{"service":"Review","item":"14286"}],["/myapi/inventory/14286",{"service":"Inventory","item":"14286"}],["/myapi/catalog/14286",{"service":"Catalog","item":"14286"}]]

Erweitern der NGINX Plus-Konfiguration zur Übersetzung von URIs

Wie bereits erwähnt, setzt die oben beschriebene minimale NGINX Plus-Konfiguration voraus, dass die API-Server URIs im Format /myapi/service/item# in /myapi/service.php/?item=item# übersetzen können. Wir können diese Übersetzung auch in der NGINX Plus-Konfiguration implementieren, indem wir die folgenden Änderungen vornehmen.

  • Fügen Sie eine neue Upstream-Gruppe hinzu, die die Unteranfragen empfängt:

    Codebeispiel wird geladen…

  • Fügen Sie einen neuen virtuellen Server hinzu, der auf Anfragen wartet, die von der Upstream-Gruppe services empfangen werden. Anfragen im Abfragezeichenfolgenformat werden einfach an die Upstream-Gruppe api_servers weitergeleitet, da der URI bereits die Erweiterung .php enthält. Bei Anfragen, deren Parameter im letzten URI-Element enthalten ist, wird der URI so umgeschrieben, dass das letzte Element aus dem URI entfernt und in ein Abfragezeichenfolgenargument umgewandelt wird:

    Codebeispiel wird geladen…

  • Ändern Sie die /myapi-Location so, dass Anfragen an die neue Upstream-Gruppe weitergeleitet werden:

    Codebeispiel wird geladen…

Hier ist die vollständige Konfiguration:

Codebeispiel wird geladen…

Zusätzliche Komponenten

Die JavaScript-Beispielprogramme und NGINX Plus-Konfigurationen können an andere API-Stile angepasst werden. Wenn Sie jedoch Tests mit allen Komponenten durchführen möchten, die zur Erstellung dieses Blogbeitrags verwendet wurden, finden Sie diese in unserem Gist-Repository auf GitHub, einschließlich der NGINX Unit-Konfiguration für die Bereitstellung der PHP-Seiten:

batch-api.js
catalog.php
inventory.php
review.php
unit.config

Fazit

Diese Beispiele zeigen, wie sich API-Anfragen bündeln und dem Client eine aggregierte Antwort bereitstellen lassen. Der Schlüssel-Wert-Speicher von NGINX Plus ermöglicht es uns, die API-Anfragen dynamisch über die NGINX Plus API zu konfigurieren. API-Systeme unterscheiden sich in ihren konkreten Abläufen erheblich, sodass dieses Beispiel auf vielfältige Weise erweitert werden kann, um die Anforderungen einer bestimmten API zu erfüllen.

Sie können NGINX-JavaScript-Unteranfragen zunächst mit NGINX Open Source testen. Wenn Sie jedoch die Beispiele für die API-Bündelung ausprobieren oder andere Anwendungsfälle testen möchten, die NGINX Plus-Funktionen wie den Schlüssel-Wert-Speicher und die NGINX Plus API nutzen, fordern Sie eine kostenlose 30-Tage-Testversion an und beginnen Sie mit Ihren Experimenten.


Teilen

Über den Autor

Rick Nelson
Rick NelsonRegional Vice President, Solution Engineering

Weitere Blogbeiträge von Rick Nelson

Ä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.