BLOG | NGINX

Einführung von HTTP/2 Server Push mit NGINX 1.13.9

NGINX-Teil-von-F5-horiz-schwarz-Typ-RGB
Owen Garrett Miniaturbild
Owen Garrett
Veröffentlicht am 20. Februar 2018

Unterstützung für HTTP/2-Server-Push ist auch in NGINX Plus R15 enthalten.

Wir freuen uns, Ihnen mitteilen zu können, dass NGINX 1.13.9 , veröffentlicht am 20. Februar 2018 , Unterstützung für HTTP/2-Server-Push bietet. Für NGINX Plus-Benutzer wird HTTP/2-Server-Push-Unterstützung in der kommenden NGINX Plus-Version R15 enthalten sein, die für April 2018 geplant ist.

Server Push, das in der HTTP/2-Spezifikation definiert ist, erlaubt es einem Server, Ressourcen proaktiv an einen Remote-Client zu senden, in dem Wissen, dass der Client diese Ressourcen bald anfordern könnte. So können Sie die Anzahl der RTTs (Round Trip Time – die Zeit für Anfrage und Antwort) bei einem Seitenladevorgang oft um eine RTT oder mehr verringern und den Nutzer damit schneller bedienen.

Mit Server-Push versorgen Sie einen Client vorab mit Stylesheets, Bildern und weiteren Ressourcen, die er zum Anzeigen einer Webseite benötigt. Achten Sie darauf, nur die tatsächlich notwendigen Ressourcen zu pushen und keine, die der Client wahrscheinlich bereits im Cache hat.

In diesem Blogbeitrag beschreibe ich:

Konfigurieren von HTTP/2 Server Push

Um beim Laden einer Seite Serverressourcen mitzuschieben, setzen Sie die Direktive http2_push folgendermaßen ein:

server { # Stellen Sie sicher, dass HTTP/2 für den Server aktiviert ist. Listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # wenn ein Client demo.html anfordert, pushen Sie auch # /style.css, /image1.jpg und /image2.jpg location = /demo.html { http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg; } }

Überprüfen des HTTP/2-Server-Push

Mit einer der beiden Methoden können Sie ganz einfach überprüfen, ob der Server-Push aktiv ist:

  • Die Entwicklertools in Ihrem Webbrowser
  • Ein HTTP/2‑Befehlszeilenclient wie nghttp

Überprüfen mit Entwicklertools (Google Chrome)

So nutzen Sie die Entwicklertools Ihres Webbrowsers, um anhand von Google Chrome zu prüfen, ob Server Push aktiv ist. Im Beispiel zeigt die Spalte Initiator im Bereich Netzwerk der Entwicklertools von Chrome, dass mehrere Ressourcen als Teil der Anforderungsweiterleitung für /demo.html an den Client übertragen wurden.

Die Spalte Initiator zeigt, dass Server-Push zum Senden von Ressourcen eingesetzt wurde

Überprüfen mit einem Befehlszeilenclient ( nghttp )

Zusätzlich zu den Webbrowser-Tools können Sie den nghttp- Befehlszeilenclient aus dem nghttp2.org -Projekt verwenden, um zu überprüfen, ob Server-Push aktiv ist. Sie können den nghttp -Befehlszeilenclient von GitHub herunterladen oder das entsprechende Betriebssystempaket installieren, sofern verfügbar. Verwenden Sie für Ubuntu das Paket nghttp2-client .

In der Ausgabe markiert das Sternchen (*) Ressourcen, die der Server aktiv bereitgestellt hat.

$ nghttp -ans https://example.com/demo.html ID AntwortEnde AnfrageStart Prozesscode Größe Anfragepfad 13 +84,25 ms +136us 84,11 ms 200 492 /demo.html 2 +84,33 ms * +84,09 ms 246us 200 266 /style.css 4 +261,94 ms * +84,12 ms 177,83 ms 200 40 K /image2.jpg 6 +685,95 ms * +84,12 ms 601,82 ms 200 173 K /image1.jpg

Serverressourcen automatisch an Clients senden

Oft ist es unbequem – oder sogar unmöglich –, die Ressourcen, die Sie pushen möchten, direkt in der NGINX-Konfigurationsdatei aufzulisten. Deshalb nutzt NGINX auch die Möglichkeit, Link-Preload-Header abzufangen und die darin erkannten Ressourcen gezielt zu pushen. Aktivieren Sie das Preloading, indem Sie die Direktive http2_push_preload in der Konfiguration hinzufügen:

server { # Stellen Sie sicher, dass HTTP/2 für den Server aktiviert ist. listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # Link-Header abfangen und angeforderte Pushes initiieren location = /myapp { proxy_pass http://upstream; http2_push_preload on; } }

Wenn NGINX beispielsweise als Proxy fungiert (für HTTP, FastCGI oder andere Datenverkehrstypen), kann der Upstream-Server seiner Antwort einen Link -Header wie diesen hinzufügen:

Verknüpfung: </style.css>; als=Stil; rel=preload

NGINX fängt diesen Header ab und leitet einen Server-Push von /style.css ein. Der Pfad im Link -Header muss absolut sein – relative Pfade wie ./style.css werden nicht unterstützt. Der Pfad kann optional eine Abfragezeichenfolge enthalten.

Um mehrere Objekte zu pushen, können Sie mehrere Link -Header angeben oder, noch besser, alle Objekte in eine durch Kommas getrennte Liste aufnehmen:

Verknüpfung: </style.css>; als=Stil; rel=preload, </favicon.ico>; als=Bild; rel=preload

Möchten Sie nicht, dass NGINX eine vorab geladene Ressource pusht, fügen Sie dem Header den Parameter nopush hinzu:

# Ressource wird nicht gepushtLink: </nginx.png>; as=image; rel=preload; nopush

Wenn http2_push_preload aktiviert ist, können Sie das Preload-Server-Push auch initiieren, indem Sie den Antwortheader in Ihrer NGINX-Konfiguration festlegen:

add_header Link "</style.css>; als=Stil; rel=preload";

Gezieltes Bereitstellen von Ressourcen für Clients

Die HTTP/2-Spezifikation löst nicht das Problem, wann Ressourcen gepusht werden sollen. Es ist am effektivsten, Ressourcen nur dann an Ihre Clients zu senden, wenn Sie sicher sind, dass sie diese wirklich brauchen und diese wahrscheinlich nicht bereits im Cache vorliegen.

Ein Ansatz könnte darin bestehen, Ressourcen nur beim ersten Besuch der Website an den Client zu senden. Prüfen Sie zum Beispiel, ob ein Sitzungscookie vorhanden ist, und setzen Sie den Link-Header nur dann, wenn kein Sitzungscookie gefunden wird. So laden Sie Ressourcen gezielt vor.

Wenn sich die Clients korrekt verhalten und das Cookie bei nachfolgenden Anfragen mitsenden, liefert NGINX die Ressourcen mit der folgenden Konfiguration pro Browsersitzung nur einmal an die Clients aus:

server {
    listen 443 ssl http2 default_server;

    ssl_certificate ssl/certificate.pem;
    ssl_certificate_key ssl/key.pem;

    root /var/www/html;
    http2_push_preload on;

    location = /demo.html {
        add_header Set-Cookie "session=1";
        add_header Link $resources;
    }
}

map $http_cookie $resources {
    "~*session=1" "";
    default "</style.css>; as=style; rel=preload, </image1.jpg>; as=image; rel=preload, </image2.jpg>; as=image; rel=preload";
}

Messen der Wirkung von HTTP/2-Server-Push

Um die Wirkung des Server-Pushs zu messen, haben wir eine einfache Testseite, /demo.html , erstellt, die auf ein separates Stylesheet, /style.css , verweist. Das Stylesheet verweist außerdem auf zwei Bilder. Wir haben die Seitenladezeiten mit drei verschiedenen Konfigurationen getestet:

  • Sequentielle GETs (ohne Optimierung) – Der Browser lädt Ressourcen sofort, wenn er ihren Bedarf erkennt
  • Preload-Hinweise – Preload-Hinweise ( Link -Header) wurden in die erste Antwort aufgenommen, um den Browser anzuweisen, die Abhängigkeiten zu laden
  • Server Push (nur HTTP/2) – Abhängigkeiten wurden präventiv an den Browser gesendet
Drei Konfigurationen wurden getestet, um die Auswirkungen von HTTP/2 mit Server-Push zu messen

Wir haben mehrere Testläufe jeder Konfiguration mit HTTP, HTTPS oder HTTP/2 durchgeführt. Die ersten beiden Konfigurationen gelten für alle drei Protokolle und Server-Push nur für HTTP/2.

Das Verhalten wurde mit den Chrome-Entwicklertools gemessen. Das am häufigsten vorkommende Verhalten jeder Konfiguration wurde bewertet und gemittelt, und die Zeiten wurden mit der RTT der Verbindung (gemessen mit Ping ) korreliert, um die mechanische Wirkung jeder Methode zu veranschaulichen.

Testergebnisse zeigen, dass bei jeder Konfiguration viele Hin- und Rückfahrten erforderlich waren

Einige grundlegende Beobachtungen

  • DOM geladen bezeichnet den Zeitpunkt, an dem Sie eine neue Verbindung herstellen und die Seite demo.html abrufen. Stylesheet beschreibt die Zeit, um die CSS-Ressource abzurufen.
  • Das Herstellen einer Verbindung über HTTP dauert 1 RTT, für HTTPS und HTTP/2 dauert es 2 RTTs.
  • Die Nutzlast der HTML- und CSS-Ressourcen ist kleiner als die maximale Transmissionsgröße (MTU), sodass Sie den GET-Vorgang in etwa einer RTT abschließen.

Interpretation der Ergebnisse: Hinweise zum Vorladen

  • Preload-Hinweise beeinflussen die CSS-Ressource kaum, weil der HTML-Ressource direkt auf sie verweist und wir die HTML-Ressource schnell ausliefern. Der Browser startet die CSS-Anfrage sofort, nachdem die HTML-Seite geliefert wurde.
  • Preload-Hinweise starten den Download von in der CSS-Ressource angegebenen Elementen (hier die zwei Bilder) deutlich schneller. Der Download beginnt mit Preload-Hinweisen bis zu 1 RTT früher.
  • Durch Preload-Hinweise sparen Sie netto mindestens 1 RTT. Beim parallelen Herunterladen von Ressourcen öffnet Ihr Browser eine oder mehrere zusätzliche Verbindungen. Die Performance hängt davon ab, ob langsame Anfragen (größere Antworten) zuerst bearbeitet werden oder verzögert, während neue Verbindungen aufgebaut werden. Diese unvorhersehbare Reihenfolge der Anfragen führt zu einer 1‑RTT-Beschleunigung bei HTTP und HTTP/2 sowie einer 2‑RTT-Beschleunigung bei HTTPS.

Interpretation der Ergebnisse: Server-Push

  • Durch Server-Push wurde die Zeit zum Vorladen der Hinweise um weitere 1 RTT verbessert. Die Push-„Antworten“ wurden gleichzeitig mit der Antwort auf die erste Anfrage initiiert, während bei den Antworten mit den Preload-Hinweisen eine Verzögerung von 1 RTT auftrat – 0,5 RTT für die Antwort auf die erste Anfrage plus 0,5 RTT für die Preload -GET -Anfrage.

Testnotizen

  • Für jede Konfiguration gab es mehrere Testläufe. Jeder Lauf begann mit einem leeren Browser-Cache und ohne hergestellte Keepalive-Verbindungen zum NGINX-Server. Die NGINX-Direktiven keepalive_timeout und http2_idle_timeout wurden verwendet, um Keepalive-Verbindungen schnell zu schließen.
  • Es scheint aktuell nicht möglich, Schriftartressourcen an Chrome zu übertragen, wahrscheinlich wegen einer bekannten Schwierigkeit. Chrome fordert eine Schriftartressource ausdrücklich an, selbst wenn wir sie bereits übertragen haben.
  • Es wurde darauf geachtet, die Browser-Caches vor jedem Test explizit zu löschen und alle Inhalte wurden mit abgelaufenen Cache-Control-Headern bereitgestellt.
  • Chrome speichert vorab geladene Ressourcen im Cache. Diese zwischengespeicherten Ressourcen werden beim Deaktivieren des Cachings nicht immer ignoriert und auch nicht zuverlässig durch eine explizite Aktion zum Löschen des Browser-Caches entfernt. (In Chrome können Sie das Caching deaktivieren, indem Sie im Reiter Netzwerk der Entwicklertools das Kontrollkästchen Cache deaktivieren aktivieren. Um den Browser-Cache zu leeren, klicken Sie mit geöffneten Entwicklertools mit der rechten Maustaste auf die Schaltfläche zum Aktualisieren und wählen Cache leeren und hart neu laden aus).
  • Manche Versuche, Inhalte vorab zu laden, brachten Chrome dazu, zwischengespeicherte Kopien vergeblich neu zu überprüfen und dann die Ressource regulär herunterzuladen. Wir haben diese Versuche in den Messungen nicht erfasst.
  • Chrome fügt allen neuen SSL-Verbindungen, die zuvor akzeptierte selbstsignierte Zertifikate verwenden, eine unnötige Verzögerung von 2 RTT hinzu. Der Test wurde mit von einer Zertifizierungsstelle signierten Let’s Encrypt-Zertifikaten durchgeführt, um diese 2-RTT-Verzögerung zu vermeiden.
  • DNS-Verzögerungen wurden durch Bearbeiten der lokalen Datei /etc/hosts behoben.
  • Diese einfachen Tests maßen nicht, wie sich Server-Push auswirkt, wenn der Client bereits eine zwischengespeicherte Kopie der Ressource besitzt. Wir haben vor jedem Test alle Caches geleert, und die meisten Pushs verliefen so schnell, dass ein Abbruch nicht nötig war.

Abschluss

Wir haben den Test bewusst einfach gestaltet, um die Funktionsweise von Preload-Hinweisen und Server Push klar zu zeigen. Server Push sorgt bei einfachen Szenarien für eine 1-RTT-Verbesserung gegenüber Preload-Hinweisen und bringt größere Vorteile im Vergleich zu nicht optimierten, sequenziellen GET-Anfragen und der Erkennung abhängiger Ressourcen.

Realistischere Anwendungsfälle bringen deutlich mehr Variablen mit sich: mehrere abhängige Ressourcen, verschiedene Quellen und sogar das Risiko, Bandbreite mit bereits zwischengespeicherten oder momentan nicht benötigten Ressourcen zu verschwenden. Auch Unterschiede zwischen Browsern beeinflussen die Leistung. Ihre Ergebnisse werden bei diesem einfachen Test wahrscheinlich abweichen.

Das Chrome-Team hat beispielsweise einige ausführliche Empfehlungen dazu veröffentlicht, wann Server-Push bereitgestellt werden sollte, und hat auf komplexeren Sites Messungen durchgeführt, um die Auswirkungen von fehlender Optimierung, Vorladehinweisen und Server-Push über HTTP/2 zu vergleichen. Ihr Bericht „Faustregeln für HTTP/2-Push“ ist für jeden lesenswert, der den Einsatz von HTTP/2-Server-Push in der Produktion erwägt.

Die pragmatische Konsequenz: Wenn Sie die benötigten Ressourcen im Voraus kennen, lohnt es sich, Upstream-Server einen Preload-Hinweis senden zu lassen. Der Nutzen dieses Pushs ist zwar gering, aber messbar; er kann jedoch Bandbreite verschwenden und die Bereitstellung wichtiger Ressourcen verzögern. Testen und überwachen Sie Server-Push-Konfigurationen deshalb sorgfältig.

Anhang: Wie funktioniert HTTP/2-Push?

Die folgenden Informationen basieren teilweise auf den Untersuchungen in Jake Archibalds sehr detailliertem Blogbeitrag „HTTP/2-Push ist schwieriger als ich dachte“ .

HTTP/2-Server-Push senden wir normalerweise abhängige Ressourcen vorab, wenn Sie eine Ressource anfragen. Fordern Sie beispielsweise eine Webseite an, schickt der Server die zugehörigen Stylesheets, Schriftarten und Bilder aktiv mit.

Wenn Sie eine HTTP/2-Verbindung herstellen, kann der Server eine oder mehrere Server-Push-Antworten initiieren. Dabei sendet der Server Ressourcen, die Sie nicht explizit angefordert haben.

Der Client kann einen Push entweder ablehnen (durch Senden eines RST_STREAM- Frames) oder akzeptieren. Der Client speichert den gepushten Inhalt in einem lokalen „Push-Cache“, der mit der HTTP/2-Verbindung verknüpft ist.

Wenn Sie später über eine bestehende HTTP/2-Verbindung eine Ressource anfordern, prüft das System den Push-Cache der Verbindung auf eine bereits abgeschlossene oder gerade übertragene Antwort. Es nutzt die zwischengespeicherte Ressource, bevor es eine neue HTTP/2-Anfrage stellt.

Eine gepushte Ressource bleibt im Push-Cache für die jeweilige Verbindung, bis (a) Sie sie verwenden oder (b) die HTTP/2-Verbindung geschlossen wird:

  1. Nutzen Sie die Ressource, erstellt der Client eine Kopie und löscht den Eintrag im Push-Cache. Ist die Ressource cachefähig, können Sie die Kopie im HTTP-Seiten-Cache speichern.
  2. Wenn die HTTP/2-Verbindung aus irgendeinem Grund geschlossen wird, wird ihr lokaler Push-Cache gelöscht.

Dies hat mehrere Auswirkungen:

  • Inhalte im HTTP-Seitencache des Browsers werden gegenüber Inhalten im Push-Cache bevorzugt verwendet, auch wenn die gepushten Inhalte aktueller sind.
  • HTTP/2-Verbindungen lassen sich über verschiedene Seitenaufrufe hinweg gemeinsam nutzen. Eine Ressource, die bei einem Seitenaufruf übertragen wird, steht Ihnen auch bei einem anderen Seitenaufruf zur Verfügung.
  • Anfragen mit Anmeldedaten nutzen andere HTTP/2-Verbindungen als solche ohne Anmeldedaten; zum Beispiel kann eine Ressource, die bei einer cross-origin Anfrage mit Anmeldedaten übertragen wird, bei einer Abfrage ohne Anmeldedaten vom Browser unter Umständen nicht gefunden werden.

Eine viel detailliertere Liste der Probleme finden Sie in Jake Archibalds Blogbeitrag „HTTP/2-Push ist schwieriger als ich dachte“ .

HTTP/2-Server-Push ist eine interessante Funktion. Stellen Sie sicher, dass Sie die Push-Konfiguration Ihres HTTP/2-Servers gründlich testen und bereit sind, in Fällen auf Preload-Hinweise zurückzugreifen, in denen dies zu einem vorhersehbareren, Cache-bewussteren Verhalten führt.


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