Meilleure priorisation HTTP / 2 pour l'accélération Web


HTTP / 2 promettait d'accélérer considérablement le Web, et Cloudflare a depuis longtemps déployé un accès HTTP / 2 pour tous les clients. Mais une caractéristique de HTTP / 2, la priorisation, n'a pas répondu aux attentes. Non pas parce qu'il est fondamentalement cassé, mais à cause de l'implémentation dans les navigateurs.

Aujourd'hui, Cloudflare suggère de changer la priorisation de HTTP / 2, ce qui donne à nos serveurs le contrôle des décisions de priorisation qui accélèrent vraiment Internet.

Historiquement, c'était le navigateur qui contrôlait comment et quand télécharger du contenu Web. Aujourd'hui, pour tous les plans payants, nous apportons des changements radicaux à ce modèle. Ils transfèrent le contrôle directement au propriétaire du site. Sur l'onglet «Vitesse» du tableau de bord Cloudflare, les clients peuvent activer la «hiérarchisation HTTP / 2 avancée»: il remplace les paramètres par défaut du navigateur par un schéma de planification amélioré, ce qui accélère considérablement l'accès des visiteurs (dans certains cas, nous avons constaté une augmentation de 50%). Avec les travailleurs Cloudflare, les propriétaires de sites peuvent aller encore plus loin et personnaliser entièrement les paramètres en fonction de leurs besoins spécifiques.

Situation actuelle


Les pages Web se composent de dizaines (parfois des centaines) de ressources individuelles qui sont téléchargées et collectées par le navigateur dans le contenu final affiché. Cela inclut le contenu visible avec lequel l'utilisateur interagit (HTML, CSS, images), ainsi que la logique d'application (JavaScript) pour le site lui-même, les balises de publicité, d'analyse et de marketing. Du point de vue de l'utilisateur, la séquence dans laquelle ces ressources sont chargées est très importante: cela affecte le moment où il voit le contenu et peut interagir avec la page.

Un navigateur est, en fait, un moteur de traitement HTML qui traverse un document HTML et suit les instructions dans l'ordre: du début à la fin du HTML, la construction de la page au fur et à mesure de ses déplacements. Les liens de feuille de style (CSS) indiquent au navigateur comment styliser le contenu de la page, et le navigateur retardera l'affichage du contenu jusqu'à ce qu'il charge la feuille de style. Les scripts sur la page peuvent avoir des comportements différents. Si le script est marqué comme «asynchrone» ou «en attente», le navigateur peut continuer à traiter le document et simplement exécuter le script lorsqu'il sera disponible. Si le script n'est pas marqué comme asynchrone ou différé, le navigateur DOIT arrêter de traiter le document jusqu'à ce que le script soit chargé et exécuté. Ces scripts sont appelés "blocage" car ils empêchent le navigateur de continuer à traiter le document.

Le document HTML est divisé en deux parties. Le titre du document <head> est au début et contient des feuilles de style, des scripts et d'autres instructions du navigateur nécessaires pour afficher le contenu. Une fois que l'en-tête est le corps du document <body>, il contient le contenu réel affiché dans la fenêtre du navigateur (bien que les scripts et les feuilles de style puissent également être dans le corps). Tant que le navigateur n'a pas atteint le corps du document, l'utilisateur n'a rien à afficher et la page reste vierge. Par conséquent, il est important de traiter l'en-tête le plus rapidement possible. Si les détails vous intéressent, le site Web HTML5 Rocks propose un excellent didacticiel sur le fonctionnement des navigateurs.

Le navigateur est généralement responsable de l'ordre dans lequel les différentes ressources nécessaires pour créer la page et poursuivre le traitement du document sont chargées. Dans HTTP / 1.x, il existe des restrictions sur le nombre d'objets que le navigateur peut demander à n'importe quel serveur à la fois (généralement 6 connexions et une seule ressource à la fois par connexion), donc l'ordre des demandes est strictement contrôlé par le navigateur. Dans HTTP / 2, la situation est complètement différente. Le navigateur peut demander toutes les ressources à la fois (au moins dès qu'il les découvre) et fournit au serveur des instructions détaillées sur la façon de fournir ces ressources.

Ordre de chargement optimal des ressources


Pour la plupart des pièces, il existe un ordre optimal dans le cycle de chargement de la page qui maximise la disponibilité de la page pour l'utilisateur (et la différence entre l'ordre de chargement optimal et non optimal peut atteindre 50% ou plus).

Comme décrit ci-dessus, avant que le navigateur puisse afficher du contenu, il est bloqué par CSS et JavaScript dans la section <head> . À ce stade, il est plus rentable d'utiliser 100% du canal pour charger les ressources de blocage, plutôt que de les charger dans l'ordre, car elles sont écrites dans le code HTML. Cela permet au navigateur d'analyser et d'exécuter chaque élément lors du chargement de la prochaine ressource de blocage, ce qui crée un pipeline optimal.



Le temps de chargement du script pour le chargement parallèle ou séquentiel ne diffère pas, mais pour le chargement séquentiel, le premier script peut être traité et exécuté lors du deuxième chargement.

Après le chargement des ressources bloquantes, la situation devient un peu plus intéressante. Ici, la charge optimale peut dépendre d'un site particulier ou même des priorités de l'entreprise (sélection de contenu généré par l'utilisateur ou de publicité, ou d'analyse, etc.). Un problème distinct avec les polices, car le navigateur détecte les polices souhaitées après avoir appliqué la feuille de style au contenu affiché. Par conséquent, au moment où le navigateur découvre la police, il est nécessaire d'afficher à l'écran du texte déjà prêt à être affiché. Tout retard dans le chargement de la police n'entraîne aucun texte à l'écran (ou le texte s'affiche dans la mauvaise police).

En règle générale, certains compromis doivent être pris en compte:

  • Les polices et images personnalisées dans la partie visible de la page (fenêtre) doivent être chargées aussi rapidement que possible. Ils affectent directement l'expérience visuelle de l'utilisateur lors du chargement de la page.
  • Le JavaScript non bloquant doit être chargé séquentiellement par rapport aux autres ressources JavaScript afin que chacune d'entre elles puisse être canalisée. JavaScript peut inclure une logique d'application personnalisée, ainsi que des balises de suivi pour l'analyse et le marketing, et leur retard peut entraîner une diminution des indicateurs suivis par l'entreprise.
  • Les images peuvent être téléchargées en parallèle. Les premiers octets du fichier image contiennent sa taille, ce qui peut être nécessaire pour la disposition du navigateur, et le chargement parallèle d'images progressives peut fournir une complétude visuelle après avoir transféré environ 50% du volume total.

Étant donné les compromis, dans la plupart des cas, cette stratégie fonctionne bien:

  • Les polices personnalisées sont téléchargées séquentiellement et partagent la bande passante disponible avec les images dans la portée.
  • Les images visibles sont chargées en parallèle, partageant entre elles la part de la bande passante qui leur est allouée.
  • Lorsqu'il n'y a plus de polices ou d'images visibles:
    • Les scripts non bloquants sont chargés séquentiellement et partagent la bande passante disponible avec des images invisibles (qui sont hors de portée).
    • Les images invisibles sont chargées en parallèle, partageant entre elles la part de la bande passante qui leur est allouée.

Ainsi, le contenu visible par l'utilisateur est chargé le plus rapidement possible, la logique d'application est retardée au minimum et les images invisibles sont chargées de manière à compléter la mise en page le plus rapidement possible.

Exemple


Pour illustrer, utilisez une page de catégorie de produit simplifiée à partir d'un site de commerce électronique typique:

  • Bleu - fichier HTML de la page elle-même.
  • Vert - Une feuille de style externe (fichier CSS).
  • Orange - Quatre scripts externes (JavaScript). Deux scripts de blocage en haut de la page et deux asynchrones. Les scripts de blocage sont affichés dans une teinte orange plus foncée.
  • Le rouge est une police Web personnalisée.
  • Violet - 13 images. Le logo de la page et quatre images de produits sont affichés dans la fenêtre de visualisation, 8 autres images de produits nécessitent un défilement. Les cinq images visibles sont indiquées par une teinte plus foncée de violet.

Par souci de simplicité, supposons que toutes les ressources ont la même taille et chaque charge en 1 seconde. Le téléchargement de toutes les ressources prend au total 20 secondes, mais l'ordre et la méthode de chargement sont extrêmement importants.



Voici à quoi ressemblera le chargement optimal des ressources dans un navigateur:



  • La page est vierge pendant les 4 premières secondes lors du chargement des scripts HTML, CSS et de blocage: ils utilisent tous une connexion à 100%.
  • À la marque de 4 secondes, l'arrière-plan et la structure de la page sont affichés sans texte ni images.
  • Après une seconde, à environ 5 secondes, le texte de la page s'affiche.
  • Dans l'intervalle de 5 à 10 secondes, les images sont téléchargées, floues au début, mais très rapidement elles deviennent claires. À environ 7 secondes, le résultat est presque impossible à distinguer de la version finale.
  • Au bout de 10 secondes environ, le chargement de tout le contenu visuel dans la partie visible de la page est terminé.
  • Au cours des deux secondes suivantes, du JavaScript asynchrone est chargé et exécuté, exécutant toute logique non critique (analytique, balises marketing, etc.).
  • Au cours des 8 dernières secondes, les images restantes sont chargées au cas où l'utilisateur ferait défiler la page.

Priorité actuelle du navigateur


Tous les moteurs de navigation actuels mettent en œuvre diverses stratégies de priorisation , dont aucune n'est optimale.

Microsoft Edge et Internet Explorer ne prennent pas en charge la hiérarchisation , ils fonctionnent donc avec les paramètres HTTP / 2 par défaut, qui chargent tout en parallèle, répartissant uniformément la bande passante entre toutes les ressources. Microsoft Edge dans les futures versions passera à l'utilisation du moteur Chromium, ce qui pourrait améliorer la situation. Mais pour l'instant, dans notre exemple, le navigateur est la plupart du temps coincé dans l'en-tête de la page, car les images ralentissent la transmission des scripts de blocage et des feuilles de style.



Visuellement, cela conduit à une expérience assez douloureuse: l'utilisateur regarde un écran vide pendant 19 secondes, puis il y a un délai de 1 seconde pour afficher le texte. Lorsque vous regardez l'animation ci-dessous, soyez patient, car pendant 19 secondes, il peut sembler que rien ne se passe sur un écran vide (bien que ce soit le cas):



Safari charge toutes les ressources en parallèle , partageant la bande passante en fonction de leur importance, selon Safari (le blocage des ressources comme les scripts et les feuilles de style est plus important que les images). Les images sont chargées en parallèle, mais aussi simultanément avec le blocage du contenu.



Bien que Safari soit similaire à Edge dans le sens où tout se charge en même temps, l'allocation de plus de bande passante aux ressources de blocage vous permet d'afficher le contenu beaucoup plus tôt:



  • Après environ 8 secondes, le chargement de la feuille de style et des scripts est terminé, vous pouvez donc commencer le rendu de la page. Étant donné que les images ont été chargées en parallèle, elles peuvent également être partiellement affichées (flou pour les images progressives). C'est toujours deux fois plus lent que le scénario optimal, mais beaucoup mieux que dans Edge.
  • Après environ 11 secondes, la police se charge. Vous pouvez afficher le texte. À ce stade, davantage de données sont chargées pour les images, et elles deviennent un peu plus nettes. Ceci est comparable à la situation autour de la marque des 7 secondes pour un scénario de chargement optimal.
  • Au cours des 9 secondes restantes, les images deviennent plus nettes à mesure que davantage de données sont téléchargées jusqu'à ce que, finalement, le processus se termine en 20 secondes.

Firefox crée une arborescence de dépendances qui regroupe les ressources, puis planifie que les groupes se chargent les uns après les autres ou partagent ensemble la bande passante entre les groupes. Au sein de ce groupe, les ressources partagent la bande passante et se chargent simultanément. Les images doivent être chargées après les feuilles de style qui bloquent le rendu et chargées en parallèle, mais les scripts et les feuilles de style qui bloquent le rendu sont également chargés en parallèle et ne bénéficient pas du pipelining.



Dans notre exemple, cela se produit un peu plus rapidement que dans Safari, car les images attendent le chargement de la feuille de style:



  • À environ 6 secondes, le contenu de la page d'origine s'affiche avec un arrière-plan et des versions floues des images du produit (contre 8 secondes pour Safari et 4 secondes dans le meilleur des cas).
  • À 8 secondes, la police est chargée et vous pouvez afficher le texte avec des images légèrement plus nettes du produit (par rapport aux 11 secondes et 7 secondes de Safari dans le meilleur des cas).
  • Pendant les 12 secondes restantes, les images deviennent plus nettes lorsque le contenu restant est chargé.

Chrome (et tous les navigateurs basés sur Chromium) priorise l'inventaire. Cela fonctionne très bien pour bloquer les ressources qui se chargent de manière optimale dans l'ordre, mais pas si bien pour les images. Chaque image est chargée à 100% avant de commencer la suivante.



En pratique, il s'agit d'un scénario de téléchargement presque optimal, à la seule différence que les images sont téléchargées une à la fois et non en parallèle:



  • Jusqu'à 5 secondes, le chargement de Chrome est identique au scénario optimal, affichant l'arrière-plan à la 4e seconde et le contenu texte à la 5e.
  • Au cours des 5 prochaines secondes, les images de la zone de visibilité sont chargées une par une jusqu'à ce que le processus se termine vers 10 secondes (par rapport au scénario optimal, lorsqu'elles sont affichées sous une forme légèrement floue vers 7 secondes et deviennent plus nettes pendant les trois secondes restantes).
  • Une fois la partie visuelle de la page terminée en 10 secondes (identique au scénario optimal), les 10 secondes restantes sont consacrées à l'exécution de scripts asynchrones et au chargement d'images cachées (ainsi que dans le scénario optimal).

Comparaison visuelle


La différence visuelle est assez différente, bien que le chargement technique de tout le contenu prenne le même temps:



Hiérarchisation côté serveur


La hiérarchisation HTTP / 2 est demandée par le client (navigateur), et le serveur doit décider quoi faire en fonction de la demande. Un grand nombre de serveurs ne prennent pas du tout en charge cette fonction et les autres répondent à une demande du client. Une autre option consiste à décider de la meilleure hiérarchisation côté serveur en fonction de la demande du client.

Selon la spécification , la hiérarchisation HTTP / 2 est un arbre de dépendance qui nécessite une connaissance complète de toutes les requêtes en cours afin de pouvoir hiérarchiser les ressources les unes par rapport aux autres. Cela vous permet de mettre en œuvre des stratégies incroyablement complexes, mais il est difficile de bien le mettre en œuvre du côté du navigateur ou du serveur (comme en témoignent les différentes stratégies du navigateur et les différents niveaux de prise en charge du serveur). Pour simplifier la gestion de la priorisation, nous avons développé un schéma plus simple qui a encore toute la flexibilité nécessaire à une planification optimale.

Le schéma de priorisation de Cloudflare se compose de 64 «niveaux» de priorité, et à chaque niveau, il existe des groupes de ressources qui déterminent comment diviser la connexion entre eux:



Tout d'abord, toutes les ressources sont téléchargées à un niveau de priorité plus élevé, puis une transition vers un niveau inférieur a lieu.

Dans un niveau de priorité donné, il existe trois groupes de simultanéité différents:

  • 0 : toutes les ressources du groupe «0» sont envoyées séquentiellement dans l'ordre dans lequel elles ont été demandées en utilisant une bande passante de 100%. Ce n'est qu'après le chargement de toutes les ressources du groupe «0» que les autres groupes du même niveau sont considérés.
  • 1 : toutes les ressources du groupe d'accès simultané «1» sont envoyées séquentiellement dans l'ordre dans lequel elles ont été demandées. La bande passante disponible est uniformément répartie entre le groupe de parallélisme "1" et le groupe de parallélisme "n".
  • n : les ressources du groupe d'accès simultané «n» sont transmises en parallèle, partageant la bande passante disponible.

En pratique, le groupe de parallélisme «0» est utile pour le contenu critique qui doit être traité séquentiellement (scripts, CSS, etc.). Le groupe «1» est utile pour les contenus moins importants qui peuvent partager la bande passante avec d'autres ressources, mais où les ressources elles-mêmes bénéficient toujours d'un traitement séquentiel (scripts asynchrones, images non progressives, etc.). Le groupe de simultanéité «n» est utile pour les ressources qui bénéficient d'un traitement parallèle (images progressives, vidéo, audio, etc.).

Priorité par défaut de Cloudflare


Avec l'option de priorisation avancée, l'ordre «optimal» de chargement des ressources, comme décrit ci-dessus, est implémenté. Les priorités spécifiques appliquées sont les suivantes:



Ce schéma vous permet d'envoyer séquentiellement des ressources qui bloquent le rendu, puis d'envoyer des images visibles en parallèle, puis le reste du contenu de la page avec un certain niveau de partage de bande passante pour équilibrer le chargement de l'application et le contenu. La mise en garde * Si détectable est que tous les navigateurs ne font pas la distinction entre les différents types de feuilles de style et de scripts, mais ce sera toujours beaucoup plus rapide dans tous les cas. Une accélération de 50%, en particulier pour les visiteurs Edge et Safari, ne sera pas inhabituelle:



Définition des priorités avec les travailleurs


Un travail par défaut plus rapide est excellent, mais il devient vraiment intéressant grâce à la possibilité de configurer la hiérarchisation avec le support Cloudflare Workers, de sorte que les sites peuvent remplacer la priorité par défaut pour les ressources ou implémenter leurs propres schémas de hiérarchisation.

Si le travailleur ajoute l'en cf-priority tête cf-priority à la réponse, les serveurs de périphérie Cloudflare appliqueront la priorité et la simultanéité spécifiées. Le format d'en-tête est <priority> / <concurrency>, donc l'en response.headers.set('cf-priority', “30/0”); définira la priorité 30 et le parallélisme 0 pour cette réponse. De même, «30/1» définira le parallélisme «1» et «30 / n» définira le parallélisme sur n.

Avec une telle flexibilité, un site peut définir une priorité arbitraire de ressources pour ses besoins. Par exemple, pour augmenter la priorité de certains scripts asynchrones importants ou images principales: ils sont téléchargés avant même que le navigateur ne détermine qu'ils sont à portée.

Pour informer sur les décisions de priorisation, le runtime des travailleurs indique également les informations demandées par le navigateur sur la priorisation dans l'objet de demande, qui est transmise au récepteur des événements de travail (request.cf.requestPriority). Les priorités entrantes sont une liste d'attributs séparés par un point-virgule. Cela ressemble à ceci: weight=192;exclusive=0;group=3;group-weight=127 .

  • poids : poids pour prioriser HTTP / 2.
  • exclusif : l'indicateur HTTP / 2 exclusif (1 pour les navigateurs basés sur Chromium, 0 pour les autres).
  • group : identifiant de flux HTTP / 2 pour le groupe de requêtes (différent de zéro pour Firefox).
  • poids du groupe : poids HTTP / 2 pour le groupe de requêtes (différent de zéro pour Firefox).

Ce n'est que le début.


La capacité de configurer et de contrôler la priorité des réponses est la pierre angulaire d'un grand travail futur. Nous avons l'intention d'introduire nos propres optimisations avancées en plus de cela, mais avec le soutien des travailleurs, tous les sites et chercheurs peuvent expérimenter différentes stratégies de priorisation. Grâce à Apps Marketplace, les entreprises peuvent également créer de nouveaux services d'optimisation au-dessus de la plate-forme de travail et les rendre disponibles pour une utilisation par d'autres sites.

Si vous êtes sur un plan Pro ou supérieur, accédez à l'onglet «Vitesse» du tableau de bord Cloudflare et activez la «hiérarchisation HTTP / 2 avancée» pour accélérer votre site.

Source: https://habr.com/ru/post/fr452020/


All Articles