# Panne d’un load balancer un vendredi soir : notre post-mortem complet

> Vingt et une heures, un vendredi, le répartiteur de charge d'un client e-commerce s'effondre en pleine promotion. Récit complet de l'incident et des correctifs qui ont suivi.

- Auteur : Clément Hadrot
- Publié le : 2025-05-07
- Mis à jour le : 2025-05-07
- Catégorie : Hébergement &amp; serveurs
- URL : https://wpmoderne.dev.wordpress-developpement.fr/hebergement/panne-load-balancer-vendredi-soir-post-mortem/

## L’essentiel

- L'incident a duré 47 minutes avant le premier correctif efficace
- La cause réelle n'était pas celle suspectée en premier
- Trois correctifs distincts ont été nécessaires pour clore l'incident

21h04, un vendredi de fin avril. Un client qui vend du mobilier en ligne lance une promotion flash relayée par une notification poussée à toute sa base d'emails. Douze minutes plus tard, le répartiteur de charge qui distribue le trafic entre les trois nœuds applicatifs du site cesse de router correctement les requêtes vers l'un des nœuds, qui continue pourtant de répondre normalement en local.

Ce post-mortem ne revient pas sur la configuration initiale de HAProxy, déjà détaillée dans un article précédent. Il raconte le déroulé précis de cet incident particulier, les fausses pistes suivies en premier, et les trois correctifs distincts qu'il a fallu appliquer avant de considérer le dossier clos.

## 21h16 : la première alerte, et la mauvaise hypothèse

La supervision remonte un taux d'erreurs 502 en hausse sur environ un tiers des requêtes. Premier réflexe : suspecter une saturation PHP-FPM sur le nœud concerné, cohérente avec le pic de trafic généré par la promotion. Les métriques du pool FPM contredisent pourtant cette hypothèse : le nombre de processus actifs reste stable, bien en dessous de `pm.max_children`. Le nœud répond correctement en interne, mais HAProxy continue de lui envoyer des requêtes qui échouent depuis l'extérieur.

Vingt minutes sont perdues à vérifier des pistes applicatives — cache d'objet, requêtes lentes en base — avant qu'un examen des journaux de HAProxy lui-même révèle l'anomalie réelle : les vérifications de santé (`health check`) configurées sur l'URL `/healthz` échouent de façon intermittente, sans rapport avec la charge réelle du nœud.

> L'essentiel à retenir : L'incident a duré 47 minutes avant le premier correctif efficace ; La cause réelle n'était pas celle suspectée en premier ; Trois correctifs distincts ont été nécessaires pour clore l'incident

## 21h42 : la vraie cause, un délai de vérification trop court

En creusant, la cause se révèle presque triviale : le délai d'attente configuré pour le health check (`timeout check 2000`) était calibré pour un trafic normal. Sous la charge de la promotion, le endpoint de santé, qui interroge la base de données pour vérifier sa disponibilité, met parfois plus de deux secondes à répondre — non pas parce que le nœud est en panne, mais parce que la connexion à MariaDB est temporairement occupée par des requêtes plus lourdes liées au pic de commandes.

HAProxy interprète ce dépassement comme un nœud défaillant, le sort du pool de répartition, puis le réintègre quelques secondes plus tard une fois le check repassé au vert — créant un effet de bascule permanent qui redistribue brutalement le trafic entre les nœuds restants et amplifie encore la charge sur chacun d'eux.

## 22h03 : premier correctif d'urgence, insuffisant

Le correctif immédiat consiste à doubler le délai d'attente du check à `timeout check 5000` et à recharger la configuration à chaud avec un signal adapté. L'effet est positif mais partiel : le taux d'erreurs baisse nettement sans disparaître complètement, car le endpoint `/healthz` reste dépendant d'une requête base de données qui n'a aucune raison logique de conditionner la disponibilité HTTP du nœud.

## 22h51 : deuxième correctif, un health check allégé

Le vrai correctif de fond consiste à séparer deux niveaux de vérification : un check HTTP léger qui confirme seulement que le serveur web répond, et un check applicatif plus complet exécuté à part par la supervision, sans conditionner le routage HAProxy. Le endpoint `/healthz` est simplifié pour ne plus interroger la base de données à chaque appel, et un endpoint distinct `/healthz/deep` conserve la vérification complète pour un usage de supervision uniquement.

- Le check HAProxy interroge désormais `/healthz`, qui répond en moins de 50 millisecondes.
- La supervision applicative continue d'interroger `/healthz/deep` toutes les cinq minutes.
- Le seuil de bascule (`fall` et `rise`) est ajusté pour tolérer deux échecs consécutifs avant retrait du pool.

## 23h12 : retour à la normale, et un troisième correctif à froid

Le trafic se stabilise définitivement à 23h12. Un troisième correctif, appliqué la semaine suivante à froid, ajoute une alerte spécifique sur les bascules répétées d'un même nœud (plus de trois sorties du pool en dix minutes), un signal qui aurait permis de détecter le problème réel bien avant les premières erreurs 502 côté client.

> Un health check ne doit jamais être plus fragile que le service qu'il est censé protéger. C'est la leçon la plus coûteuse de cet incident.

## Ce que nous en retenons

Trois correctifs distincts ont été nécessaires : un ajustement de délai en urgence, une refonte du endpoint de santé, et une alerte de détection des bascules anormales. Aucun des trois pris isolément n'aurait suffi. La documentation de HAProxy sur les vérifications de santé mérite d'être relue régulièrement, tant les valeurs par défaut se révèlent inadaptées dès qu'un trafic devient irrégulier : [haproxy.org/download](https://www.haproxy.org/download/2.9/doc/configuration.txt).
