Keep-alive et connexions persistantes

La latence réseau a un impact très important sur les performances. Si les ressources sont zippées, que vos images sont correctement compressées, et que les fichiers textes sont minimisés, la latence peut devenir presque plus pénalisante que les téléchargements eux même.

Au niveau du contenu

L’utilisation de javascript ou CSS concaténées et d’images en sprites diminuera l’impact de la latence par rapport au téléchargement lui même. L’utilisation d’un CDN diminuera la distance réseau entre vos serveurs et vos utilisateurs et réduira la latence elle-même.

Malheureusement vous aurez encore besoin d’au moins un fichier CSS, un fichier javascript, et probablement une bonne dizaine d’images au minimum. Cela fait douze requêtes. Avec un ping honnête de 40 ms, voilà une demi seconde qui part en fumée [1]. Inacceptable.

[1] Et par respect pour l’intervention de Rik sur un précédent billet, je signale que cette demi seconde est théorique, en pratique certains délais sont parallélisés donc ne délaieront pas d’autant le rendu de la page. L’impact reste cependant important, d’autant que votre site professionnel contient plus de douze ressources à télécharger non ?

Au niveau du réseau

Vos navigateurs ont heureusement deux mécanismes qui peuvent compenser notre demi seconde : keep-alive et pipelining. Nous parlerons ici du keep-alive, le pipelining sera pour demain.

Le keep-alive c’est le nom des connexions persistantes en HTTP. A partir de HTTP 1.1, par défaut votre serveur laisse la connexion ouverte après avoir répondu à une requête. Le navigateur peut alors relancer une nouvelle requête sur la même connexion, sans avoir à rétablir un nouvel échange TCP. C’est tout ça de gagné, et ce n’est pas négligeable.

La problématique

Les connexions persistantes sont un des réglages avec un fort impact sur les performances, sur lesquels on n’arrive pas à dégager un consensus.

La problématique est la suivante : une connexion persistante c’est une connexion qui reste ouverte pendant un certain temps « au cas où le navigateur ait encore des requêtes à faire ». Or une connexion ouverte a un impact négatif sur les performances du serveur. C’est un lien réseau ouvert et un processus avec son occupation mémoire. Un processus Apache avec PHP c’est généralement 5 à 10 Mo de mémoire vive. On ne peut pas en bloquer des centaines juste « pour attendre au cas où ». Si on surcharge le serveur, il répond plus lentement et au final les performances du client se dégradent aussi.

Une bonne pratique peut déjà être de réduire la durée valeur du keep-alive par défaut, c’est à dire la durée pendant laquelle le serveur garde la connexion ouverte en attente d’une nouvelle requête du navigateur. Par défaut Apache la règle à 5 secondes (15 secondes sur les anciennes versions).

La difficulté est de trouver un bon équilibre entre cette fonctionnalité qui aide le client et les performances du serveur. Sachant que le gain pour le client est significatif mais pas critique, le compromis est trop souvent un refuge vers la situation la moins risquée « on désactive tout keep-alive sur le serveur ».

Une recommandation rapide

Une recommandation générique (je m’attends donc à ce que chacun me dise qu’il est dans une situation tierce) serait de désactiver le keep-alive sur les serveurs de contenu principaux, et de l’activer avec quelques secondes sur les CDN.

En considérant que vos images et fichiers tiers sont sur les CDN, vous ne devriez avoir qu’un seul téléchargement par page sur le serveur de contenu principal : la page HTML. Inutile d’activer le keep-alive et d’attendre d’autres requêtes si on sait qu’il y a des chances qu’il n’y en ait pas d’autres de si tôt. De plus ces serveurs gèrent des requêtes dynamiques, donc embarquent souvent des langages de script. Chaque processus prend beaucoup de mémoire, les connexions persistantes coûteraient cher.

Sur les CDN la problématique s’inverse. On y télécharge tous les fichiers tiers, probablement plus d’une dizaine par page quand le cache est vide. Garder la connexion ouverte est intéressant pour le client comme pour le serveur. Ce sont aussi des serveurs qui n’envoient que des fichiers statiques, l’empreinte mémoire et le coût d’un processus qui reste en attente sont probablement beaucoup plus faibles.

Deux autres options

Une autre option, plus simple, est de mettre un proxy inversé devant votre serveur web. C’est lui qui va garder les connexions persistantes avec les navigateurs, et les processus d’un proxy ne coûtent pas très chers.

Le serveur web Apache propose aussi un module expérimental : MPM Event. Il permet d’utiliser un seul processus unique avec une file de connexions pour gérer les keep-alive, au lieu de bloquer un processus entier à chaque connexion persistante.

Votre solution

J’ai entendu dire tout et son contraire. Si vous avez fait des recherches ou simplement si vous avez testé plusieurs options, je suis curieux de connaitre vos conclusions et votre situation.

Pour l’instant j’ai surtout vu les trois solutions citées, dans le même ordre de préférence :

  • Le plus souvent : on désactive tout, parce que le keep-alive est parfois plus négatif que positif, donc on joue la sécurité.
  • Pas de keep-alive sur les serveurs dynamiques, mais un keep-alive moyen sur les serveurs statiques.
  • Dans quelques cas un keep-alive assez long, mais géré par un proxy ou un serveur intermédiaire.

 

Publié par edaspet

Plus d'informations sur mon profil en ligne

3 réponses sur « Keep-alive et connexions persistantes »

  1. Je n’aurais pas pensé au proxy parce que je n’ai pas assez de savoir dans ce domaine, mais l’idée est séduisante. Par contre dans tous les cas, la seconde solution me semble couler de source et parfaitement rationnelle.

  2. A ce sujet, le serveur NginX (que j’utilise beaucoup en guise de reverse proxy pour les pages dynamiques) utilise une valeur de 65 secondes par défaut. Je n’ai pas creusé plus que ça, mais je suppose qu’il s’agit là de prévoir les cas de chargement différé via Javascript durant une minute tout en laissant une petite marge de 5 secondes.

    Ce choix me semble assez judicieux, surtout avec du HTTPS où la connexion est assez lente, non ?

    Sinon je confirme « mon utilisation » : pour les petits sites je déploie généralement du Apache2-event, et pour le reste la connexion keep alive est laissée à la charge d’NginX uniquement.

Les commentaires sont fermés.