BLOG | NGINX

Présentation du serveur HTTP/2 Push avec NGINX 1.13.9

NGINX-Partie-de-F5-horiz-black-type-RGB
Vignette d'Owen Garrett
Owen Garrett
Publié le 20 février 2018

La prise en charge du push serveur HTTP/2 est également incluse dans NGINX Plus R15 .

Nous sommes ravis d'annoncer que NGINX 1.13.9 , publié le 20 février 2018 , inclut la prise en charge du push serveur HTTP/2. Pour les utilisateurs de NGINX Plus, la prise en charge du push serveur HTTP/2 sera incluse dans la prochaine version NGINX Plus R15 , prévue pour avril 2018.

Le push serveur, défini dans la spécification HTTP/2 , permet à un serveur de pousser de manière préventive des ressources vers un client distant, en anticipant que le client pourrait bientôt demander ces ressources. Ce faisant, vous pouvez potentiellement réduire le nombre de RTT (temps d’aller-retour – le temps nécessaire pour une demande et une réponse) dans une opération de chargement de page d’un RTT ou plus, offrant ainsi une réponse plus rapide à l’utilisateur.

Le serveur push peut être utilisé pour préparer un client avec des feuilles de style, des images et d'autres ressources dont il aura besoin pour restituer une page Web. Vous devez veiller à n’envoyer que les ressources nécessaires ; n’envoyez pas des ressources qu’un client est susceptible d’avoir déjà mises en cache.

Dans cet article de blog, je décris :

Configuration du push du serveur HTTP/2

Pour envoyer des ressources avec le chargement d’une page, utilisez la directive http2_push comme suit :

server { # Assurez-vous que HTTP/2 est activé pour le serveur listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # chaque fois qu'un client demande demo.html, envoyez également # /style.css, /image1.jpg et /image2.jpg location = /demo.html { http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg; } }

Vérification du push du serveur HTTP/2

Vous pouvez facilement vérifier que le push du serveur est en vigueur en utilisant l'une des deux méthodes suivantes :

  • Les outils de développement dans votre navigateur Web
  • Un client HTTP/2 en ligne de commande tel que nghttp

Vérification avec les outils de développement (Google Chrome)

Voici comment utiliser les outils de développement de votre navigateur Web pour vérifier que la fonction Push du serveur est en vigueur, en utilisant Google Chrome comme exemple. Dans la figure, la colonne Initiateur de l'onglet Réseau des outils de développement de Chrome indique que plusieurs ressources ont été transmises au client dans le cadre d'une demande pour /demo.html .

La colonne Initiateur indique que le serveur push a été utilisé pour envoyer des ressources

Vérification avec un client de ligne de commande ( nghttp )

En plus des outils de navigateur Web, vous pouvez utiliser le client de ligne de commande nghttp du projet nghttp2.org pour vérifier que la transmission du serveur est effective. Vous pouvez télécharger le client de ligne de commande nghttp depuis GitHub ou installer le package de système d’exploitation approprié lorsqu’il est disponible. Pour Ubuntu, utilisez le package nghttp2-client .

Dans la sortie, l'astérisque (*) marque les ressources qui ont été poussées par le serveur.

$ nghttp -ans https://example.com/demo.html id responseEnd requestStart processus code taille requête chemin 13 +84.25ms +136us 84.11ms 200 492 /demo.html 2 +84.33ms * +84.09ms 246us 200 266 /style.css 4 +261.94ms * +84.12ms 177.83ms 200 40K /image2.jpg 6 +685.95ms * +84.12ms 601.82ms 200 173K /image1.jpg

Envoi automatique de ressources aux clients

Dans de nombreuses situations, il est peu pratique, voire impossible, de répertorier les ressources que vous souhaitez pousser dans le fichier de configuration NGINX. Pour cette raison, NGINX prend également en charge la convention d'interception des en-têtes de préchargement de lien , puis de transmission des ressources identifiées dans ces en-têtes. Pour activer le préchargement, incluez la directive http2_push_preload dans la configuration :

server { # Assurez-vous que HTTP/2 est activé pour le serveur listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # Intercepter l'en-tête du lien et lancer les push demandés location = /myapp { proxy_pass http://upstream; http2_push_preload on; } }

Par exemple, lorsque NGINX fonctionne comme un proxy (pour HTTP, FastCGI ou d’autres types de trafic), le serveur en amont peut ajouter un en-tête de lien comme celui-ci à sa réponse :

Lien : </style.css> ; as=style ; rel=preload

NGINX intercepte cet en-tête et lance un push serveur de /style.css . Le chemin dans l'en-tête du lien doit être absolu – les chemins relatifs comme ./style.css ne sont pas pris en charge. Le chemin peut éventuellement inclure une chaîne de requête.

Pour envoyer plusieurs objets, vous pouvez fournir plusieurs en-têtes de lien ou, mieux encore, inclure tous les objets dans une liste séparée par des virgules :

Lien : </style.css>; as=style; rel=preload, </favicon.ico>; as=image; rel=preload

Si vous ne souhaitez pas que NGINX envoie une ressource préchargée, ajoutez le paramètre nopush à l'en-tête :

# La ressource n'est pas pousséeLien : </nginx.png>; as=image; rel=preload; nopush

Lorsque http2_push_preload est activé, vous pouvez également lancer le push du serveur de préchargement en définissant l'en-tête de réponse dans votre configuration NGINX :

add_header Lien "</style.css>; as=style; rel=preload";

Transférer sélectivement des ressources aux clients

La spécification HTTP/2 n’aborde pas le défi consistant à déterminer s’il faut ou non pousser les ressources. De toute évidence, il est préférable de ne transmettre des ressources aux clients que si vous savez à la fois qu’ils sont susceptibles d’en avoir besoin et qu’il est peu probable qu’ils l’aient déjà mise en cache.

Une approche possible consiste à proposer des ressources aux clients uniquement lors de leur première visite sur le site. Vous pouvez tester la présence d'un cookie de session, par exemple, et définir l'en-tête Link de manière conditionnelle, de sorte que les ressources ne soient préchargées que si le cookie de session n'est pas présent.

En supposant que les clients se comportent bien et incluent le cookie dans les requêtes ultérieures, avec la configuration suivante, NGINX transmet les ressources aux clients une seule fois par session de navigateur :

serveur {
écoute 443 ssl http2 default_server;

certificat_ssl ssl/certificate.pem;
clé_certificate_ssl ssl/key.pem;

racine /var/www/html;
http2_push_preload activé;

emplacement = /demo.html {
add_header Set-Cookie "session=1";
add_header Lien $ressources;
}
}

map $http_cookie $ressources {
"~*session=1" "";
par défaut "</style.css>; as=style; rel=preload, </image1.jpg>; as=image; rel=preload, </image2.jpg>; as=image; rel=preload";
}

Mesurer l'effet du push du serveur HTTP/2

Pour mesurer l'effet du push serveur, nous avons créé une page de test simple, /demo.html , qui fait référence à une feuille de style distincte, /style.css . La feuille de style fait également référence à deux images. Nous avons testé les temps de chargement des pages en utilisant trois configurations différentes :

  • GET séquentiels (pas d'optimisation) – Le navigateur a chargé les ressources lorsqu'il a découvert qu'elles étaient nécessaires
  • Conseils de préchargement – Des conseils de préchargement (en-têtes de lien ) ont été inclus dans la première réponse pour indiquer au navigateur de charger les dépendances
  • Server Push (HTTP/2 uniquement) – Les dépendances ont été poussées de manière préventive vers le navigateur
Trois configurations ont été testées pour mesurer l'impact de HTTP/2 avec le push serveur

Nous avons effectué plusieurs tests de chaque configuration en utilisant HTTP, HTTPS ou HTTP/2. Les deux premières configurations s'appliquent aux trois protocoles et le serveur envoie uniquement des données vers HTTP/2.

Le comportement a été mesuré à l’aide des outils de développement Chrome. Le comportement le plus courant de chaque configuration a été évalué et moyenné, et les temps ont été corrélés avec le RTT du lien (mesuré à l'aide de ping ) pour illustrer l'effet mécanique de chaque méthode.

Les résultats des tests montrent que de nombreux allers-retours ont été effectués avec chaque configuration

Quelques observations de base

  • Le DOM chargé est le moment d'initier une nouvelle connexion et de récupérer la page demo.html . La feuille de style est le moment de récupérer la ressource CSS.
  • L'établissement d'une connexion via HTTP nécessite 1 RTT ; pour HTTPS et HTTP/2, il faut 2 RTT.
  • La charge utile des ressources HTML et CSS est inférieure à la taille de l'unité de transmission maximale (MTU), de sorte qu'une opération GET s'exécute en environ 1 RTT.

Interprétation des résultats : Conseils de préchargement

  • Les conseils de préchargement ont un effet minimal sur la ressource CSS car elle est directement référencée dans la ressource HTML et la ressource HTML est livrée rapidement. Le navigateur initie la requête CSS dès que la page HTML est livrée.
  • Les conseils de préchargement ont pour effet de démarrer rapidement le téléchargement des ressources déclarées dans la ressource CSS (ici, les deux images). Les téléchargements peuvent démarrer 1 RTT plus rapidement lorsque des conseils de préchargement sont utilisés.
  • Les économies nettes réalisées grâce aux conseils de préchargement peuvent être de 1 RTT ou plus. Lors du téléchargement de ressources en parallèle, le navigateur doit ouvrir une ou plusieurs connexions supplémentaires. Les performances dépendent du fait que les requêtes lentes (réponses plus longues) sont planifiées en premier ou qu'elles sont retardées pendant l'ouverture de nouvelles connexions. Cet ordre de requête imprévisible explique l’accélération du 1-RTT pour HTTP et HTTP/2, et l’accélération du 2-RTT pour HTTPS.

Interprétation des résultats : Poussée du serveur

  • Le serveur push a amélioré le temps de préchargement des indications d'un RTT supplémentaire. Les « réponses » push ont été initiées en même temps que la réponse à la première requête, tandis que les réponses preload-hints ont subi un délai RTT de 1 – 0,5 RTT pour la réponse à la première requête plus 0,5 RTT pour la requête GET de préchargement.

Notes de test

  • Plusieurs tests ont été effectués pour chaque configuration. Chaque exécution a commencé avec un cache de navigateur vide et sans connexions keepalive établies avec le serveur NGINX. Les directives NGINX keepalive_timeout et http2_idle_timeout ont été utilisées pour fermer rapidement les connexions keepalive.
  • Il ne semble actuellement pas possible de transférer des ressources de polices vers Chrome, peut-être en raison d'une complication connue . Chrome fait une demande explicite pour une ressource de police même si elle a déjà été poussée.
  • Des précautions ont été prises pour effacer explicitement les caches du navigateur avant chaque test, et tout le contenu a été diffusé avec des en-têtes de contrôle de cache expirés.
  • Chrome met en cache les ressources préchargées. Ces ressources mises en cache ne sont pas systématiquement ignorées lorsque vous désactivez la mise en cache et ne sont pas systématiquement effacées par une opération explicite de « vidage du cache du navigateur ». (Dans Chrome, une façon de désactiver la mise en cache consiste à cocher la case Désactiver le cache dans l’onglet Réseau des outils de développement. Pour vider le cache du navigateur, vous pouvez cliquer avec le bouton droit sur le bouton d’actualisation du navigateur avec les outils de développement ouverts et sélectionner Vider le cache et recharger à froid ).
  • Certaines tentatives de préchargement de contenu ont amené Chrome à revalider sans succès les copies mises en cache, puis à télécharger la ressource normalement. Ces tentatives n’ont pas été comptabilisées dans les mesures.
  • Chrome ajoute un délai 2-RTT inutile à toutes les nouvelles connexions SSL qui utilisent des certificats auto-signés précédemment acceptés. Le test a été réalisé à l’aide de certificats Let’s Encrypt signés par une autorité de certification pour éviter ce délai de 2 RTT.
  • Les retards DNS ont été résolus en modifiant le fichier local /etc/hosts .
  • Ces tests simples n’ont pas tenté de mesurer l’effet du push du serveur lorsque le client dispose déjà d’une copie en cache de la ressource. Lors des tests, tous les caches ont été vidés avant chaque test et la plupart des pushs ont été trop rapides pour être annulés.

Conclusion

Ce test a été volontairement simple, afin de mettre en évidence les mécanismes des indices de préchargement et du push serveur. Le push serveur offre une amélioration de 1-RTT par rapport aux indications de préchargement dans des situations simples, et une amélioration plus importante par rapport aux requêtes GET séquentielles non optimisées et à la découverte de ressources dépendantes.

Les cas d’utilisation plus réalistes comportent beaucoup plus de variables : plusieurs ressources dépendantes, plusieurs sources, voire la possibilité d’un gaspillage de bande passante en poussant des ressources déjà mises en cache ou qui ne sont pas immédiatement nécessaires. Les incohérences du navigateur affectent également les performances. Votre kilométrage variera certainement par rapport à ce simple test.

Par exemple, l'équipe Chrome a publié des recommandations détaillées sur le moment de déployer le push serveur et a effectué des mesures sur des sites plus complexes pour comparer les effets de l'absence d'optimisation, des conseils de préchargement et du push serveur sur HTTP/2. Leur rapport Rules of Thumb for HTTP/2 Push mérite d'être lu par quiconque envisage de déployer le serveur HTTP/2 Push en production.

La conclusion pragmatique est que si vous pouvez identifier à l’avance les ressources nécessaires, il y a un réel avantage à ce que les serveurs en amont envoient une indication de préchargement. L’avantage supplémentaire de pousser ces ressources est faible mais mesurable, mais peut éventuellement entraîner un gaspillage de bande passante et des retards pour les ressources nécessaires. Vous devez tester et surveiller attentivement toutes les configurations de serveur push.

Annexe : Comment fonctionne HTTP/2 Push ?

Les informations ci-dessous sont basées en partie sur les recherches effectuées dans l'article de blog très détaillé de Jake Archibald intitulé HTTP/2 push is tougher than I thought .

Le push du serveur HTTP/2 est généralement utilisé pour envoyer des ressources dépendantes de manière préventive lorsque le client demande une ressource. Par exemple, si un client demande une page Web, le serveur peut envoyer des feuilles de style, des polices et des images dépendantes au client.

Lorsqu'un client établit une connexion HTTP/2, le serveur peut choisir de lancer une ou plusieurs réponses push du serveur via la connexion. Ces push envoient des ressources que le client n'a pas explicitement demandées.

Le client peut soit rejeter un push (en envoyant une trame RST_STREAM ) soit l'accepter. Le client stocke le contenu poussé dans un « cache push » local associé à la connexion HTTP/2.

Plus tard, lorsque le client effectue une demande de ressource à l’aide d’une connexion HTTP/2 établie, il vérifie le cache push de la connexion pour obtenir une réponse terminée ou en transit à la demande. Il utilise la ressource mise en cache plutôt que de faire une nouvelle requête HTTP/2 pour la ressource.

Toute ressource poussée reste dans le cache push par connexion jusqu'à ce que (a) elle soit utilisée ou (b) la connexion HTTP/2 soit fermée :

  1. Si la ressource est utilisée, le client prend une copie et l'entrée dans le cache push est supprimée. Si la ressource peut être mise en cache, le client peut alors mettre en cache sa copie dans son cache de page HTTP.
  2. Si la connexion HTTP/2 est fermée pour une raison quelconque, son cache push local est supprimé.

Cela a plusieurs implications :

  • Le contenu du cache de page HTTP dans le navigateur est utilisé de préférence au contenu du cache push, même si le contenu poussé est plus récent.
  • Les connexions HTTP/2 peuvent être partagées entre différents chargements de pages. Une ressource poussée à la suite du chargement d'une page peut être utilisée lorsqu'elle est demandée dans un chargement de page différent.
  • Les requêtes avec informations d'identification utilisent des connexions HTTP/2 différentes des requêtes sans informations d'identification ; par exemple, une ressource envoyée avec une requête inter-origines (avec informations d'identification) peut ne pas être trouvée si le navigateur effectue une requête non authentifiée pour la ressource.

Vous pouvez consulter une liste beaucoup plus détaillée des problèmes dans l'article de blog de Jake Archibald, HTTP/2 push is tougher than I thought .

Le push du serveur HTTP/2 est une fonctionnalité intéressante. Assurez-vous de tester minutieusement la configuration push de votre serveur HTTP/2 et soyez prêt à recourir aux indications de préchargement dans les cas où cela donne un comportement plus prévisible et plus sensible au cache.


« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."