Blog What We Do Support Community
Developers
Login Sign up

Améliorer le TTFB du HTML

by Patrick Meenan.

Le délai de réception du premier octet (« Time to First Byte », ou « TTFB ») d'un site désigne le temps écoulé entre le moment où l'utilisateur commence à naviguer et celui où commence à arriver le code HTML de la page qu'il demande. Le TTFB trop lent est le fléau de mon existence depuis plus de dix ans que j'utilise

Si le TTFB figure parmi les quelques éléments d'évaluation sur lesquels se base WebpPageTest pour noter un site, c'est qu'il y a une bonne raison. Et s'il est le premier d'entre eux, c'est également pour une bonne raison.

Si le délai de réception du premier octet est long, TOUS les autres indicateurs seront ralentis. Fait rare : en l'améliorant, on peut prédire quelles seront les répercussions sur tous les autres indicateurs. Chaque milliseconde d'amélioration du TTFB se traduit directement par une milliseconde de réduction pour tous les autres indicateurs (c'est-à-dire que le premier arrière-plan apparaîtra 500 ms plus vite si le TTFB est raccourci de 500 ms). Cela dit, ce n'est pas parce que le TTFB est rapide que tout est rapide, mais l'inverse est vrai. Je dirais qu'environ 50 % de toutes les demandes d'aide relatives aux résultats de WebPageTest proviennent de webmasters confrontés à un TTFB trop lent.

Le TTFB peut contenir de nombreux éléments, parmi lesquels les redirections, le DNS, la configuration de la connexion, la négociation SSL et le temps de réponse réel du serveur. La plupart d'entre eux peuvent être corrigés relativement facilement en utilisant un service comme Cloudflare, mais le temps de réponse du serveur pour le HTML lui-même est souvent le plus gros problème et le plus difficile à résoudre.

Le diagramme en cascade ci-dessous montre le temps de réponse du serveur sous la forme d'une barre bleu clair à la première requête. Lorsqu'il est lent, cela ne se voit que trop bien. Dans des conditions optimales, le temps de réponse du serveur ne serait pas plus long que la barre orange représentant la connexion au socket qui le précède immédiatement.

Plus de trois secondes pour que le serveur réponde.

La lenteur des temps de réponse d'origine peut être due à une multitude de problèmes allant de la configuration du serveur, de la charge du système, des bases de données back-end et des systèmes auxquels il parle, au code applicatif lui-même. Pour enrayer les problèmes de performances à la racine, les équipes d'ingénieurs DevOps travaillent généralement avec des outils de gestion des performances des applications pour repérer les éléments les plus lents de l'application et les améliorer.

Une grande partie des administrateurs de sites avec lesquels j'ai travaillé n'ont pas les ressources ou l'expertise nécessaires pour mener ce genre d'enquête. Dans la plupart des cas, ils ont payé un spécialiste pour le développement de leur site, ou l'ont développé eux-mêmes sur WordPress et l'hébergent sur un service d'hébergement bon marché. En général, les solutions d'hébergement sont conçues pour gérer autant de sites que possible, pas nécessairement pour obtenir des performances optimales.

Mise en cache périphérique du HTML

Le fait est que la plupart des contenus HTML ne sont pas vraiment dynamiques. Ils doivent pouvoir changer relativement rapidement lorsque le site est mis à jour, mais, pour une grande partie du Web, le contenu reste statique pendant des mois ou des années.

Dans certains cas particuliers, comme lorsqu'un utilisateur est connecté (administrateur ou autre), le contenu doit être différent, mais la grande majorité des visites sont effectuées par des utilisateurs anonymes. Si le HTML peut être mis en cache et transmis directement à partir de la périphérie, les gains de performance peuvent être substantiels (plus de 3 secondes plus rapides sur tous les indicateurs).

Un temps de réponse du serveur beaucoup plus rapide.

Il existe des douzaines de plugins pour WordPress permettant de mettre en cache le contenu à l'origine, mais ils nécessitent une configuration (où mettre les pages en cache) et les performances dépendent toujours fortement des performances du service d'hébergement lui-même. Le fait de déplacer le cache de contenu un peu plus vers la périphérie réduit la complexité, élimine le temps supplémentaire nécessaire pour revenir à l'origine et exclut complètement du calcul les performances du service d'hébergement. Il peut également réduire considérablement la charge pesant sur les systèmes d'hébergement en supprimant la totalité du trafic anonyme.

Cloudflare prend en charge la mise en cache HTML statique, et les clients professionnels et les entreprises peuvent permettre aux utilisateurs connectés d'ignorer le cache en activant le « contournement du cache des cookies ». Cette fonctionnalité interagit avec le plugin Cloudflare pour WordPress afin que le cache puisse être effacé chaque fois que le contenu est mis à jour. Il existe également plusieurs autres plugins de mise en cache qui s'intègrent avec différents RDC, mais dans tous les cas, ils doivent être configurés avec des clés API pour RDC et les implémentations sont spécifiques à chaque RDC.

Mise en cache périphérique du HTML sans configuration

Pour une adoption massive, nous devons faire en sorte que la mise en cache du HTML se fasse automatiquement (ou le plus automatiquement possible). Pour cela, nous avons besoin d'un moyen de communiquer entre une origine (comme un site WordPress) et un cache périphérique (comme les nœuds périphériques de Cloudflare) pour gérer un cache distant pouvant être purgé facilement.

L’origine doit être capable de :

  • savoir quand un cache périphérique compatible se trouve devant elle ;
  • préciser le contenu qui doit être mis en cache et pour quels visiteurs (c'est-à-dire ceux sans cookie de connexion) ;
  • purger le contenu du cache lorsqu'il a changé (au niveau de toutes les zones périphériques).

Au lieu de demander à l'origine de s'intégrer avec une API pour purger les modifications et de nécessiter une configuration manuelle pour savoir quoi mettre en cache et quand nous pouvons tout accomplir en utilisant des en-têtes HTTP sur les requêtes qui font des allers-retours entre la périphérie et l'origine :

1 - Un en-tête HTTP est ajouté aux requêtes allant de la périphérie à l'origine pour annoncer la présence d'un cache périphérique et des fonctionnalités qu'il peut prendre en charge :

x-HTML-Edge-Cache: supports=cache|purgeall|bypass-cookies

2 - Lorsque l'origine répond avec une page pouvant être mise en cache, elle ajoute un en-tête HTTP à la réponse pour indiquer qu'elle doit être mise en cache et préciser toute consigne concernant les situations où la version en cache ne doit pas être utilisée (pour permettre aux utilisateurs connectés d'éviter la mise en cache) :

x-HTML-Edge-Cache: cache,bypass-cookies=wp-|wordpress

Dans ce cas, le HTML sera mis en cache, mais toutes les requêtes dont les cookies ont un nom commençant par « wordpress » ou « wp- », car le nom du cookie contournera le cache et ira à l'origine.

3 - Lorsqu'une requête modifie le contenu du site (mise à jour d'un message, modification d'un thème, ajout d'un commentaire), l'origine ajoute un en-tête de réponse HTTP indiquant que le cache doit être purgé :

x-HTML-Edge-Cache: purgeall

Seul point délicat : la purge doit purger le cache de TOUTES les zones périphériques, et pas seulement de la zone par laquelle est passée la requête.

4 - Lorsqu'une nouvelle requête de HTML se trouvant dans le cache périphérique est reçue, les cookies de requête sont vérifiés par rapport aux critères de réponse en cache. Si les cookies ne sont pas présents, la version en cache est envoyée ; dans le cas contraire, la requête est transmise à l'origine.

Grâce à cette interface de commande et de contrôle simple reposant sur des en-têtes, plus besoin d'une origine pour communiquer avec une API ou d'une configuration spécifique. Cela rend également la logique sur l'origine beaucoup plus facile à implémenter, car il n'y a pas de configuration (ou d'UI) et pas de nécessité de requêtes sortantes vers une API propre à un fournisseur. Le plugin WordPress en exemple compte moins de 50 lignes de code, dont la grande majorité consiste à connecter des rappels pour tous les événements qui modifient le contenu.

Commencez à utiliser la mise en cache dès aujourd'hui avec WordPress et Workers

L'une des choses que j'aime le plus avec Workers, c'est que vous obtenez une zone périphérique totalement programmable qui vous permet de tester vos idées et d'appliquer votre propre logique. J’ai créé un script Worker qui implémente le protocole basé sur les en-têtes et la mise en cache dans les zones périphériques de Cloudflare, et un plugin WordPress qui implémente la logique de l’origine pour WordPress.

Le seul problème avec le Worker a été de trouver un moyen de purger tous les éléments du cache. Les caches Worker sont propres à chaque zone périphérique et ne disposent pas d'une interface permettant d'effectuer des opérations au niveau global. Il est possible de le faire en utilisant l'API Cloudflare pour purger le cache global, mais la purge de tout le cache, y compris des scripts et des images, est un peu lourde et nécessite une certaine configuration. Si vous connaissez précisément les URL qui seront modifiées par un changement de contenu, la meilleure solution serait probablement de procéder à une purge ciblée via l'API uniquement pour ces URL.

Avec le nouveau magasin de données Workers KV, nous pouvons purger la cache d'une autre manière. Le script Worker utilise un schéma de gestion des versions pour le cache qui attribue un numéro de version à chaque URL (par exemple, http://www.example.com/?cf_edge_cache_ver=32). L'URL modifiée n'est utilisée que localement par le worker comme clé pour les réponses mises en cache, et le numéro de version actuel est stocké dans KV, un magasin de données global. Lorsque le cache est purgé, le numéro de version passe au suivant, ce qui modifie l'URL pour toutes les ressources. Les anciennes écritures seront retirées du cache, car elles ne seront plus accessibles. Il est nécessaire de configurer un peu KV pour pouvoir utiliser le worker, mais on peut espérer que cela devienne automatique à l'avenir.

Et ensuite ?

Je pense que le Web aurait grand intérêt à normaliser un moyen de communication entre les caches périphériques et les origines pour que le contenu dynamique puisse être mis en cache. Cela inciterait les systèmes de gestion de contenu à intégrer la prise en charge directement dans les plates-formes et à fournir une interface standard qui pourrait être utilisée par différents fournisseurs (et même pour les caches périphériques locaux dans les équilibreurs de charge ou d'autres proxies inverses). Après avoir effectué d'autres tests avec différents types de sites, je pense proposer le concept au groupe de travail HTTP de l'IETF pour voir si nous pouvons nous mettre d'accord sur une norme officielle en matière d'en-têtes de contrôle (en utilisant différents noms). Si vous avez des idées concernant son fonctionnement ou les fonctionnalités dont vous auriez besoin, je serais ravi de les connaître (comme la purge d'URL spécifiques, la modification du contenu selon le type d'appareil ou la zone géographique, son extension à tous types de contenus, etc).

comments powered by Disqus