Le groupe électrogène que personne n'a jamais démarré
Une ville sérieuse double ce qui ne peut pas s'arrêter. Deux conduites d'eau maillées plutôt qu'une antenne unique, deux arrivées sur le poste électrique, un groupe électrogène dans le sous-sol de l'hôpital.
Le groupe est là depuis douze ans. Réservoir plein, contrat d'entretien, autocollant de contrôle à jour. Personne ne l'a jamais démarré en coupant vraiment le courant de l'étage, parce que couper vraiment le courant de l'étage, c'est risqué.
Le jour de la coupure, trois découvertes arrivent en même temps. La batterie de démarrage est morte. L'inverseur de source bascule, mais le bloc opératoire n'était pas raccordé au bon départ. Et le tableau de supervision qui devait donner l'alerte est branché sur le circuit tombé.
C'est l'histoire de la plupart des architectures dites hautement disponibles. Le matériel de secours existe, il est facturé tous les mois, et son état réel est inconnu.
La disponibilité ne s'achète pas avec du matériel en double. Elle se construit en supprimant les points de défaillance uniques, puis en prouvant régulièrement que le double fonctionne.
Redondance, réplication, bascule
Trois leviers, dans cet ordre, et aucun ne sert seul.
La redondance garantit qu'un second exemplaire du composant existe. La réplication garantit que ce second exemplaire détient les données nécessaires pour servir. La bascule garantit que le trafic part effectivement vers lui, assez vite, et sans que les deux exemplaires se mettent à travailler chacun de leur côté.
Une redondance sans réplication donne une machine vide qui répond des erreurs. Une réplication sans bascule donne une copie parfaite que personne n'interroge. Une bascule sans quorum donne deux primaires qui divergent.
un second exemplaire existe"] R --> RE["Réplication
le second détient les données"] RE --> B["Bascule
le trafic part vers le second"] B --> S["Service rendu"] R -.-> M1["Sans réplication
une machine vide"] RE -.-> M2["Sans bascule
un secours jamais sollicité"] B -.-> M3["Sans quorum
deux primaires qui divergent"] classDef levier fill:#b5651d,stroke:#8a4d16,color:#f5f2ec; classDef etat fill:#d89253,stroke:#8a4d16,color:#2c3338; classDef echec fill:#a0413e,stroke:#8a4d16,color:#f5f2ec; class R,RE,B levier; class P,S etat; class M1,M2,M3 echec;
Avant les trois leviers, il y a un chiffre. Sans lui, la conversation tourne en rond entre des gens qui veulent tous « que ça ne tombe jamais » sans dire combien ils sont prêts à payer pour ça.
Redondance, réplication, bascule forment une chaîne. Le maillon manquant est presque toujours le troisième, parce que c'est le seul qui demande de provoquer volontairement une panne pour être vérifié.
Chiffrer la disponibilité
Une régie des eaux ne promet pas que l'eau coule toujours. Elle publie un nombre d'heures de coupure tolérées par an, et un délai d'intervention. C'est plus honnête, et surtout c'est vérifiable.
La disponibilité se compte en pourcentage de temps de service sur une période, en général l'année. Le calcul de base tient en une ligne.
365 jours x 24 heures x 60 minutes = 525 600 minutes par an
99 % -> 1 % de 525 600 = 5 256 min = 87,6 h = 3,65 jours
99,9 % -> 0,1 % de 525 600 = 525,6 min = 8,76 h
99,99 % -> 0,01 % de 525 600 = 52,56 min
99,999 % -> 0,001 % de 525 600 = 5,26 min = 315 secondes
Chaque neuf supplémentaire divise l'indisponibilité par dix et multiplie la facture par beaucoup plus. Ramené au mois, l'écart devient parlant.
| Niveau | Indisponibilité par an | Par mois | Ce que ça impose |
|---|---|---|---|
| 99 % | 3,65 jours | 7,3 heures | Une astreinte et une procédure manuelle |
| 99,9 % | 8,76 heures | 43,8 minutes | De la redondance à chaque étage, une bascule outillée |
| 99,99 % | 52,6 minutes | 4,4 minutes | Une bascule automatique, une détection en secondes |
| 99,999 % | 5,3 minutes | 26 secondes | Plusieurs sites actifs, aucun humain dans la boucle |
Regarde la dernière ligne. Vingt-six secondes par mois, c'est moins que le temps de lire une alerte. À ce niveau, toute intervention humaine dans le chemin de reprise consomme à elle seule le budget annuel.
Le piège arrive ensuite. Un système n'est pas un composant, c'est une chaîne de composants en série, et les disponibilités se multiplient.
Chaîne en série, cinq composants à 99,9 % chacun :
0,999 ^ 5 = 0,995 009 9 soit 99,50 %
Indisponibilité = 0,499 % de 525 600 min = 2 623 minutes = 43,7 heures par an
Cinq briques irréprochables à trois neuf produisent un service à deux neuf et demi. Le raccourci mental à retenir : sur des composants très disponibles, les indisponibilités s'additionnent. Cinq fois 0,1 %, c'est 0,5 %, et l'approximation suffit largement en réunion.
La redondance joue dans l'autre sens. Deux exemplaires en parallèle ne tombent ensemble que si les deux tombent.
Deux exemplaires à 99 % chacun, pannes indépendantes, bascule parfaite :
indisponibilité combinée = 0,01 x 0,01 = 0,000 1 soit 99,99 %
Deux hypothèses viennent d'être posées, et elles sont fausses toutes les deux. Les pannes sont rarement indépendantes, et la bascule n'est jamais parfaite. Le scénario B de ce billet ne parle que de ça.
La disponibilité est l'une des -ilities traitées dans Les *-ilities : traduire les exigences en capacités techniques. Ce billet-ci en traite la mise en œuvre : ce qu'il faut construire pour tenir le nombre de neuf annoncé.
Le nombre de neuf n'est pas une ambition, c'est un budget. Il détermine le nombre de sites, le mode de réplication et le degré d'automatisation. On l'écrit avant de concevoir, pas après l'incident.
Supprimer le point de défaillance unique
Une ville reliée au reste du monde par un seul pont a beau aligner les hôpitaux et les casernes, elle est coupée quand le pont l'est. Le point de défaillance unique ne se cherche pas dans la liste des serveurs, il se cherche sur le chemin.
La méthode est mécanique. On suit une requête de bout en bout, du navigateur jusqu'à l'octet écrit sur disque, et à chaque étape on pose la même question : si celui-là s'arrête maintenant, que se passe-t-il ?
| Étage | Point unique typique | Parade |
|---|---|---|
| Résolution de nom | une seule zone chez un seul hébergeur DNS | deux fournisseurs, TTL choisis en connaissance de cause |
| Entrée réseau | un seul lien, un seul transitaire | deux liens, deux opérateurs |
| Répartiteur de charge | une instance unique en tête de chaîne | paire avec adresse virtuelle, ou service managé réparti |
| Application | un processus unique, de l'état en mémoire locale | plusieurs instances sans état |
| Cache | une instance unique, une clé chaude | cluster de caches, et un chemin qui fonctionne sans cache |
| Base de données | un primaire unique | réplique promouvable, quorum |
| Coordination | un cluster unique de découverte de services | isolation par domaine de panne, mode dégradé |
| Certificats | une expiration commune à tout le parc | renouvellement automatique et surveillance des échéances |
| Humain | une seule personne qui sait basculer | procédure écrite, exercice périodique |
Deux étages passent presque toujours à la trappe. Le DNS, parce qu'il paraît gratuit et permanent. Et la couche de coordination, parce qu'elle est perçue comme de la plomberie plutôt que comme une dépendance de production.
Le répartiteur mérite une attention particulière : il supprime le point unique côté applicatif tout en le déplaçant sur lui-même. Le sujet est traité en détail dans Répartiteur de charge, proxy et proxy inverse.
Aucun inventaire de matériel ne révèle un point de défaillance unique. On le trouve en suivant une requête et en demandant, à chaque étape, ce qui reste debout quand cette étape ne répond plus.
La redondance : actif/passif ou actif/actif
La ville a deux dispositifs de secours qui ne fonctionnent pas du tout pareil. Le groupe électrogène de l'hôpital ne sert à rien 364 jours par an, et tout dépend de lui le 365e. Les deux conduites d'eau maillées, elles, portent l'eau tous les jours, chacune sa part.
En actif/passif, une instance sert le trafic, l'autre attend. Le basculement demande une action, la capacité de secours dort, et son état réel reste inconnu jusqu'au jour où on en a besoin.
En actif/actif, toutes les instances servent en permanence. La panne de l'une d'elles se traduit par une redistribution, pas par une bascule. Le secours se teste tout seul, puisqu'il travaille.
| Critère | Actif/passif | Actif/actif |
|---|---|---|
| Capacité utilisée en régime normal | la moitié, au mieux | la totalité |
| Délai de reprise | le temps de la détection plus celui de la promotion | le temps de retirer un nœud du pool |
| Complexité applicative | faible, un seul écrivain | forte, écritures concurrentes à arbitrer |
| État du secours | inconnu entre deux exercices | vérifié en continu |
| Sensibilité à la donnée partagée | modérée | élevée, la cohérence devient le sujet |
L'actif/actif a une contrainte de dimensionnement que beaucoup découvrent le jour de la panne. Deux sites qui tournent chacun à 60 % de leur capacité ne survivent pas à la perte de l'un des deux : le survivant récupère la totalité du trafic, soit 120 % de ce qu'il sait faire, et tombe à son tour.
N sites actifs, un site perdu, trafic total T :
chaque site restant absorbe T / (N - 1)
capacité à acheter au total = T x N / (N - 1)
N = 2 -> 2,00 x T
N = 3 -> 1,50 x T
N = 4 -> 1,33 x T
Le calcul explique pourquoi les architectures multi-sites sérieuses en alignent trois plutôt que deux. À deux sites, la haute disponibilité coûte le double de la capacité utile. À trois, elle coûte 50 % de plus, et le troisième site sert aussi d'arbitre pour le quorum.
Entre les deux modes, il existe une nuance utile : le N+1. On dimensionne N instances pour la charge, on en exploite N+1, et la perte d'une seule ne dégrade rien. C'est de l'actif/actif au sens du trafic, et du surdimensionnement assumé au sens du budget.
L'actif/passif achète de la simplicité et paie en incertitude. L'actif/actif achète de la certitude et paie en cohérence à gérer. Les deux coûtent la même capacité matérielle.
La réplication : ce qu'on accepte de perdre
La seconde conduite d'eau peut être maintenue en pression en permanence, prête à prendre le relais en une fraction de seconde. Elle peut aussi être laissée vide, à remplir le jour où on en a besoin. Le premier choix coûte cher tous les jours, le second coûte une heure sans eau.
C'est exactement l'arbitrage de la réplication, et il se formule avec deux nombres.
Le RPO (recovery point objective, point de récupération) répond à : combien de données acceptons-nous de perdre ? Le RTO (recovery time objective, temps de récupération) répond à : combien de temps acceptons-nous d'être arrêtés ?
Un RPO de zéro impose que chaque écriture soit confirmée par la copie avant d'être annoncée au client. Un RPO de trente secondes autorise une réplication qui traîne.
Réplication asynchrone, retard mesuré à 3 secondes.
Charge d'écriture : 2 000 écritures par seconde.
Écritures perdues si le primaire disparaît maintenant :
3 s x 2 000 = 6 000 écritures
Six mille écritures, cela se compte en commandes payées et non enregistrées, en messages envoyés et disparus, en débits appliqués d'un côté et pas de l'autre.
La réplication synchrone supprime cette perte, et facture la distance. La contrainte est physique, pas logicielle.
Deux sites distants de 500 km.
Vitesse de propagation dans une fibre : environ 200 000 km/s.
Aller-retour = 2 x 500 / 200 000 = 0,005 s = 5 ms
Chaque écriture paie ces 5 ms avant tout traitement.
Une transaction qui enchaîne 4 écritures paie 20 ms de plancher incompressible.
Aucun réglage ne rachète ces millisecondes. Elles se déduisent du budget de latence de la requête entière, et elles fixent une limite dure au débit d'écriture d'une transaction séquentielle.
| Mode | RPO | Effet sur l'écriture | Ce qui casse |
|---|---|---|---|
| Asynchrone | le retard de réplication observé | aucun | perte des dernières écritures à la bascule |
| Semi-synchrone, une réplique acquitte | proche de zéro tant qu'une réplique suit | un aller-retour | une réplique lente ralentit le primaire |
| Synchrone sur toutes les répliques | zéro | l'aller-retour de la plus lente | une seule réplique en difficulté bloque tout |
PostgreSQL expose ce curseur directement, avec synchronous_commit et synchronous_standby_names : on choisit combien de répliques doivent confirmer, et lesquelles. Le paramètre a l'air anodin dans un fichier de configuration. Il décide en réalité du comportement du service le jour de la panne.
Ce curseur est celui du théorème CAP, posé au niveau de la base. Exiger la confirmation d'un site distant, c'est refuser les écritures quand le lien se coupe. Le raisonnement complet est dans Le théorème CAP, ACID et BASE.
RPO et RTO ne sont pas des indicateurs d'exploitation, ce sont des décisions produit. Tant que personne du métier n'a dit combien de secondes de commandes sont perdables, l'équipe technique choisit à sa place, sans le savoir.
La bascule : détecter, décider, promouvoir, revenir
L'inverseur de source d'un bâtiment fait quatre choses en quelques secondes. Il constate l'absence de tension, il vérifie que ce n'est pas un simple clignotement, il commute vers le groupe, et il refuse absolument que les deux sources alimentent le réseau en même temps.
Une bascule logicielle a le même programme, et les mêmes quatre occasions d'échouer.
Détecter. Le contrôle de santé décide de tout, et son réglage est un compromis nu.
backend api
option httpchk GET /health
default-server inter 2s fall 3 rise 2
server api1 10.0.1.11:8080 check
server api2 10.0.1.12:8080 check backup
Ici, inter 2s avec fall 3 signifie trois sondes en échec espacées de deux secondes : six secondes avant qu'un serveur soit retiré. rise 2 impose deux succès, soit quatre secondes, avant qu'il soit réintégré. Le mot-clé backup sur la seconde ligne server décrit un actif/passif : ce serveur ne reçoit du trafic que si l'autre est déclaré mort.
Raccourcis trop, tu évinces des instances saines à chaque hoquet réseau. Rallonge trop, tu sers des erreurs pendant une minute. Et si tu sondes une page qui se contente de renvoyer 200 sans rien vérifier, tu ne détectes jamais rien.
Décider. La promotion ne se fait jamais sur la parole d'un seul nœud, qui peut être celui qui est isolé du reste. Elle exige une majorité stricte.
Quorum = majorité stricte = partie entière de (N / 2) + 1
N = 3 -> quorum 2 -> tolère 1 panne
N = 4 -> quorum 3 -> tolère 1 panne (aucun gain sur N = 3)
N = 5 -> quorum 3 -> tolère 2 pannes
La ligne N = 4 explique pourquoi les clusters de coordination se comptent en nombres impairs. Le quatrième nœud ajoute du coût et de la latence sans améliorer la tolérance.
Promouvoir. Une réplique devient primaire, et le trafic d'écriture doit la trouver. Adresse IP virtuelle, mise à jour dans la découverte de services, reconfiguration du proxy, ou changement d'enregistrement DNS. Cette dernière option est la plus lente : un TTL de 300 secondes signifie que des clients continueront d'écrire vers l'ancienne adresse pendant cinq minutes, et ces cinq minutes appartiennent au RTO.
L'étape d'isolation décide de tout. Sans elle, l'ancien primaire qui revient à lui continue d'accepter des écritures pendant que le nouveau en accepte d'autres : les deux jeux divergent, et aucune fusion automatique ne les réconciliera. C'est le double maître, le split brain, et il n'a que trois parades sérieuses. Le quorum, qui empêche une minorité de se promouvoir. L'isolation forcée du nœud suspect, coupure d'alimentation ou révocation d'accès au stockage. Et l'arbitre externe, placé dans un troisième domaine de panne, qui tranche quand deux sites ne se voient plus.
Revenir. Le retour à la normale est l'étape la plus sous-estimée. L'ancien primaire ne se rebranche pas : il se reconstruit à partir du nouveau, sous peine de réinjecter ses écritures orphelines. Et le retour de trafic se fait progressivement, parce que les caches sont froids, les files pleines et les clients en train de rejouer leurs requêtes en attente.
Une bascule automatique mal réglée cause plus d'incidents qu'elle n'en résout. Avant d'automatiser la promotion, automatise la détection, puis regarde pendant un trimestre combien de fois elle se serait déclenchée à tort.
Ce qui casse en vrai
Les architectures hautement disponibles échouent rarement là où le schéma le prévoit. Cinq motifs reviennent.
La bascule jamais testée. Elle a été conçue en 2022, validée sur un environnement de recette, et jamais rejouée depuis. Entre-temps, deux versions de base de données, un changement de réseau et le départ de la personne qui l'avait écrite.
La dépendance cachée. L'outil de supervision tourne sur l'infrastructure qu'il surveille. Le dépôt d'artefacts nécessaire pour redémarrer un service est hébergé derrière ce service. Le VPN d'accès à la console s'authentifie contre l'annuaire qui vient de tomber. Chacune de ces boucles transforme une panne de dix minutes en panne de dix heures.
La panne corrélée. Le calcul de tout à l'heure supposait des pannes indépendantes. Trois répliques exécutant le même binaire, avec la même configuration, sur le même modèle de disque, mises à jour le même jour, ne forment pas trois chances indépendantes. C'est un seul exemplaire recopié trois fois.
Le retour à la normale. La reprise de trafic sur des caches vides multiplie la charge sur la base par un facteur que personne n'a estimé. Les clients qui rejouent leurs requêtes en attente arrivent tous à la même seconde. Beaucoup d'incidents comptent deux creux : la panne, puis la reprise.
Le secours sous-dimensionné. Le site de secours a été taillé pour un plan de continuité écrit il y a trois ans, quand le trafic valait la moitié. Il tient huit minutes.
La redondance protège d'une défaillance matérielle isolée. Elle ne protège ni d'un défaut logiciel partagé, ni d'une erreur de configuration déployée partout, ni d'une dépendance circulaire. Ces trois-là causent les longues pannes.
Scénario B : Roblox, 73 heures sans service
Le 28 octobre 2021, Roblox devient inaccessible. Le service n'est complètement rétabli que le 31, soit environ 73 heures plus tard. En janvier 2022, Roblox et HashiCorp publient un rapport technique commun d'un niveau de détail rare pour ce type d'exercice.
Le contexte compte. Roblox exploite son infrastructure dans ses propres centres de données, avec la pile HashiCorp : Nomad pour l'ordonnancement des charges, Consul pour la découverte de services et la coordination, Vault pour les secrets. Consul y tient le rôle de socle : c'est par lui que les services se trouvent les uns les autres.
Le rapport décrit deux facteurs qui se combinent. D'abord l'activation d'une fonctionnalité de diffusion (streaming) de Consul, censée améliorer la propagation des changements, qui sous forte charge a provoqué une contention importante sur les serveurs du cluster. Ensuite un comportement de BoltDB, le moteur de persistance utilisé pour le journal Raft de Consul, dont la gestion de la liste des pages libres dégradait fortement les performances d'écriture dans les conditions rencontrées.
Le cluster Consul était pourtant redondé, avec plusieurs serveurs et un consensus Raft. Cette redondance n'a rien protégé, pour la raison exposée plus haut : toutes les répliques exécutaient le même logiciel, avec la même configuration, et ont donc rencontré exactement le même problème au même moment.
La suite est instructive sur la difficulté du diagnostic. L'équipe a d'abord suspecté le matériel et déplacé le cluster vers des machines plus performantes, sans résoudre le problème. Le rapport signale aussi que l'investigation a été ralentie par le fait que les systèmes de télémétrie s'appuyaient sur la même infrastructure que celle qu'ils devaient observer, et que leur mise à l'écart figure parmi les actions engagées ensuite.
La remise en service a été menée de façon graduelle et contrôlée, service par service, précisément pour éviter que le retour du trafic ne fasse retomber l'ensemble.
Deux enseignements directement transposables. La redondance ne protège pas d'un défaut logiciel partagé par toutes les répliques. Et une couche de coordination centrale, aussi redondée soit-elle, reste un point de défaillance unique déguisé : tout ce qui en dépend tombe avec elle.
Points clés
- La disponibilité se calcule avant de se concevoir. 525 600 minutes par an, un neuf de plus divise l'indisponibilité par dix et fixe le budget d'automatisation.
- Les composants en série multiplient leurs disponibilités : cinq briques à 99,9 % donnent un service à 99,5 %, soit 43,7 heures d'arrêt annuel au lieu de 8,76.
- L'actif/actif à deux sites coûte deux fois la capacité utile. À trois sites, il n'en coûte plus que 1,5 fois, et le troisième sert d'arbitre.
- Le mode de réplication fixe le RPO, et la distance entre sites fixe un plancher physique de latence d'écriture qu'aucun réglage ne rachète.
- Une bascule se juge sur son quorum, son isolation du nœud déchu et son retour à la normale, pas sur la présence d'une seconde machine dans le schéma.
Dans la série
Palier 2 : Faire circuler. Domaine : Flux & fiabilité.
- Précédent : Limitation de débit et idempotence : encaisser les rejeux
- Suivant : Sharding et hachage cohérent : découper sans tout déménager
- Vue d'ensemble : System design : par où commencer
Pour aller plus loin
- Répartiteur de charge, proxy et proxy inverse, pour le composant qui détecte les instances mortes et les retire du chemin.
- Le théorème CAP, ACID et BASE : ce qu'on accepte de perdre, pour l'arbitrage qui se cache derrière le choix synchrone ou asynchrone.
- Les *-ilities : traduire les exigences en capacités techniques, pour la disponibilité vue comme exigence non-fonctionnelle à écrire noir sur blanc.
- Le rapport commun Roblox et HashiCorp sur la panne d'octobre 2021, à lire en entier, c'est un des meilleurs post-mortem publics.
- Documentation PostgreSQL sur la haute disponibilité et la réplication, pour les modes de réplication et leurs paramètres réels.
- Embracing Risk, chapitre du Site Reliability Engineering de Google, pour la façon de transformer un objectif de disponibilité en budget d'erreur.