Chapitre 6.5Le répartiteur de charge

Répartir le trafic sur plusieurs serveurs.

4 minutes de lecture

Nous avons vu qu'un serveur est un logiciel qui attend des requêtes et y répond. Tant qu'il y a dix visiteurs, tout va bien. À dix mille en même temps, la machine sature, les réponses s'allongent, puis plus rien ne sort du tout.

Il faut donc plusieurs machines. Et dès qu'il y en a plusieurs, une question se pose, celle de savoir qui reçoit quoi. C'est le travail du répartiteur de charge, que tu entendras presque toujours appeler par son nom anglais, le load balancer.

Grandir en hauteur ou en largeur

Face à un système qui sature, il n'existe que deux réponses.

  • Grandir en hauteur : prendre une machine plus puissante, avec plus de processeurs et plus de mémoire. C'est simple, ça ne demande de changer aucune ligne de code, et ça s'arrête vite. Les très grosses machines coûtent extrêmement cher, et il existe toujours une taille maximale.
  • Grandir en largeur : ajouter des machines identiques à côté de la première. Il n'y a plus de plafond, on continue d'en ajouter tant qu'on en a besoin, et une panne n'emporte plus tout le service.

La seconde approche est celle qui a gagné, et c'est elle qui rend indispensable un intermédiaire chargé de distribuer le travail.

Le principe

Imagine la file unique d'un bureau de poste. Les clients ne choisissent pas leur guichet, ils se présentent à une seule file, et une personne les oriente vers le guichet libre. Personne n'attend derrière quelqu'un qui remplit un formulaire de vingt minutes pendant que le guichet d'à côté tourne à vide.

Le répartiteur de charge fait exactement ça. Il se place devant tes serveurs et devient le seul point de contact visible depuis Internet. Ton nom de domaine pointe vers lui, pas vers tes machines. Il reçoit chaque requête et la transmet à l'un des serveurs qui se tiennent derrière, puis renvoie la réponse au visiteur.

Vu du navigateur, rien n'a changé. Il y a toujours une seule adresse, un seul site, une seule réponse. Que trois ou trois cents machines travaillent derrière ne le regarde pas, et c'est précisément l'intérêt.

Une adresse, trois machines
              visiteurs
         ▼    ▼    ▼    ▼    ▼
     ┌─────────────────────────┐
     │  répartiteur de charge  │  mon-site.com pointe ici
     └───┬─────────┬─────────┬─┘
         ▼         ▼         ▼
    serveur 1  serveur 2  serveur 3  même code partout
         └─────────┼─────────┘
                   ▼
            base de données          unique, elle

Comment il choisit la machine

Plusieurs stratégies existent, et tu croiseras leurs noms dans une configuration ou dans une discussion technique.

  • Le tour de rôle : chacun son tour, dans l'ordre. C'est le réglage par défaut, et il convient très bien quand toutes les machines sont identiques et toutes les requêtes équivalentes.
  • Le moins chargé : le répartiteur regarde combien de requêtes chaque serveur traite déjà et envoie la suivante au moins occupé. Plus juste dès que certaines requêtes coûtent beaucoup plus cher que d'autres.
  • Par poids : on donne une part plus grande aux machines les plus puissantes. Pratique quand le parc n'est pas homogène, par exemple pendant un renouvellement de serveurs.
  • Par provenance : le même visiteur retombe systématiquement sur la même machine. On appelle ça la session collante, et nous allons voir que c'est une fausse bonne idée.

Le contrôle de santé

C'est la fonction la plus utile du répartiteur, et paradoxalement celle dont on parle le moins.

Toutes les quelques secondes, il interroge chacune de ses machines sur une adresse prévue pour ça, souvent quelque chose comme /sante. Si l'une d'elles ne répond plus, ou répond une erreur, elle est immédiatement retirée de la rotation. Le répartiteur continue de la sonder, et la remet en service dès qu'elle va mieux.

Exemple :

Un de tes quatre serveurs sature un mardi matin et cesse de répondre. Sans répartiteur, un visiteur sur quatre tombe sur une page d'erreur, et tu l'apprends par le support client. Avec un répartiteur, la machine sort du circuit en quelques secondes, les trois autres absorbent le trafic, personne ne voit rien, et c'est ton outil de supervision qui te prévient.

Ce mécanisme est aussi ce qui rend possible une mise en production sans coupure. On sort une machine de la rotation, on installe la nouvelle version dessus, on vérifie, on la remet, puis on passe à la suivante. Les visiteurs continuent d'être servis pendant toute l'opération. C'est exactement ce que décrit le chapitre sur la mise en production continue.

Le piège de la session collante

Souviens-toi que le protocole HTTP est sans état, et que le serveur ne se souvient de rien entre deux requêtes. Si ton application range malgré tout le panier ou la session de connexion dans la mémoire de la machine qui a répondu, alors cette machine devient irremplaçable pour ce visiteur.

On règle ça en collant chaque visiteur à un serveur précis. Ça fonctionne, et ça crée trois problèmes.

  • La répartition devient inégale, puisqu'on ne distribue plus les requêtes mais les visiteurs, qui n'ont pas tous la même activité.
  • Quand une machine tombe, ses visiteurs perdent leur panier et leur connexion, au lieu d'être simplement servis ailleurs.
  • Chaque mise en production déconnecte une partie des utilisateurs, ce qui pousse l'équipe à livrer la nuit, donc moins souvent.

La bonne réponse n'est pas de mieux coller les visiteurs, c'est de sortir l'état de la machine. La session part dans un cache partagé ou dans un jeton, les fichiers déposés partent dans un stockage commun, et n'importe quel serveur redevient capable de répondre à n'importe qui. Le jour où une équipe technique explique qu'elle doit faire ce chantier avant de pouvoir monter en charge, elle parle de ça.

Où se cache un répartiteur

Tu en croises beaucoup plus souvent que tu ne le crois, et sous des formes très différentes.

  • Chez ton hébergeur : les offres cloud proposent toutes un répartiteur managé, facturé quelques dizaines d'euros par mois, qu'on active en cochant une case.
  • Dans un logiciel : des serveurs web comme Nginx ou HAProxy savent faire ce travail depuis des années, sur une machine que tu administres toi-même.
  • Devant le tout : un CDN joue aussi ce rôle à l'échelle de la planète, en dirigeant chaque visiteur vers le point de présence le plus proche avant même que la requête n'atteigne ton infrastructure.
  • Dans le DNS : la forme la plus rustique consiste à déclarer plusieurs adresses IP pour un même nom de domaine. Ça répartit grossièrement, mais le DNS ignore totalement l'état de tes machines et continuera d'envoyer des visiteurs vers un serveur mort tant que le cache n'a pas expiré.

Ce qu'il ne fait pas

Le répartiteur multiplie les serveurs qui exécutent ton code. Il ne multiplie pas ce qu'il y a derrière.

Ta base de données, elle, reste le plus souvent unique, et c'est elle qui devient le point de saturation suivant. Ajouter des machines devant une base déjà à genoux ne fait qu'accélérer le moment où elle tombe. C'est d'ailleurs la raison pour laquelle le cache arrive presque toujours avant le répartiteur dans l'ordre des optimisations, parce qu'il soulage la source au lieu de la solliciter davantage.

Autre limite, souvent oubliée dans l'enthousiasme, le répartiteur lui-même devient le passage obligé de tout ton trafic. S'il tombe, tout tombe, même si les dix serveurs derrière se portent à merveille. Les offres sérieuses le doublent donc en interne, et c'est un point à vérifier dans un contrat plutôt qu'à découvrir un dimanche soir.

La question à poser à ton équipe n'est pas "est-ce qu'on a un load balancer", mais "que se passe-t-il si une machine tombe pendant les soldes". La réponse te dira tout de suite si la mise à l'échelle a été pensée, ou seulement achetée.

PrécédentFrameworks et bibliothèques Tous les chapitres