Les trois concepts de défaillance à connaître
Bienvenue
Les systèmes distribués défaillent selon des modèles. Une fois que vous connaissez ces modèles, chaque post-mortem devient un exercice de reconnaissance au lieu d'être un mystère.
Trois concepts couvrent la plupart de ce qui compte dans l'analyse des échecs de production :
Point unique de défaillance (SPOF): un composant dont l'échec entraîne la baisse d'un système plus large. Ce sont souvent des cachettes : le serveur DNS sur lequel tout le monde dépend ; le certificat contre lequel tout se renouvelle ; le maître de base de données unique.
Défaillance en cascade: l'échec d'un composant déclenche celui d'un autre, qui déclenche celui d'un autre. Une base de données lente provoque des temps morts dans le niveau API, ce qui provoque des tentatives de réessaie, ce qui charge encore plus la base de données, ce qui provoque encore plus de temps morts. L'action se propage.
Rayon d'action: combien de la partie du système s'arrête lorsque une pièce échoue. Les choix architecturaux limitent ou non le rayon. Un SPOF a un rayon d'action non limité. Un service à bulkheads a un rayon limité.
À la fin de cette leçon, vous serez capable de :
- Identifier les SPOFs dans une architecture par inspection
- Reconnaître les modèles de défaillance en cascade : troupeau tonnerre, ouragan de réessaie, file d'attente de la mort
- Lire un véritable calendrier et séparer le déclencheur de la défectueuse latente que le déclencheur a mise en surface
- Écrire des éléments d'action sans faute qui ciblent les systèmes au lieu des personnes, couvrant la prévention / détection / récupération
- Réfléchir aux bulkheads et aux interrupteurs de courant comme des outils limitant le rayon d'action
Repérez le point unique de défaillance
Inspection de l'architecture en couches
Considérez une petite architecture web :
- DNS : api.example.com -> IP unique du serveur nom 203.0.113.10 hébergé par un seul fournisseur DNS
- CDN : un seul fournisseur CDN devant api.example.com
- Ingress : deux machines de proxy inverses derrière un équilibreur de charge
- Backend : six instances API dans deux zones de disponibilité (trois par zone)
- Base de données : une principale + une replica de lecture, dans la même zone de disponibilité
- Cache : cluster Redis, trois nœuds répartis dans les mêmes deux zones de disponibilité
Question : quelles composantes sont des SPOFs ? Contraire : les SPOFs ne sont pas toujours évidents 'seul machine' de sorte. Un cluster de trois machines toutes dans une même zone de disponibilité est un SPOF pour l'échec de la zone de disponibilité.
Trois modèles de cascade classiques
Les pannes se propagent par les dépendances
Modèle 1 : Troupe de tonnerre. Un resource partagée (cache, verrou, base de données) rate ou redémarre. Chaque client qui en dépend tente de reprendre simultanément. La vague submerge ce qui reprend vie ; les tentatives de reprise s'accumulent plus vite que la récupération ne peut les absorber ; la récupération ne se termine jamais.
Modèle 2 : Tempête de reprise. Un service en aval ralentit. Les appels upstream, au lieu de rater, réessaient. Les reprises se multiplient par la charge d'origine. Le service ralentit davantage, déclenchant plus de reprises. Finalement, la charge dépasse même une version saine du service.
Modèle 3 : File de mort. Une file de traitement sans surpression reçoit plus vite qu'elle ne traite. La file augmente sans limite. La mémoire s'épuise ; le consommateur rate ; redémarre ; trouve une file encore plus grande ; rate à nouveau.
Fil conducteur : une petite perturbation initiale déclenche un boucle à feedback positif. La réponse du système amplifie la panne plutôt que d'en atténuer.
Mécanismes d'atténuation
Retard exponentiel avec bruit. Les clients qui re essaient attendent plus longtemps à chaque fois, avec une offset aléatoire. Empêche les vagues synchronisées de reprise.
Circuit brise. Un appelant suit le taux de panne en aval. Au-delà d'un seuil, l'appelant arrête d'appeler pendant une période de refroidissement et échoue immédiatement ses propres demandes.
Coque. Isoler les resources par dépendance. Piscine A pour la base de données, piscine B pour le cache. Une base de données lente ne peut pas étrangler toutes les connexions ; les appels au cache continuent.
Élimination de la charge. Lorsqu'elle est surchargée, rejeter les demandes au niveau de l'extérieur plutôt que d'accepter et de rater lentement. Un 429 en 1 ms est mieux qu'un 500 en 30 secondes.
Surpression. Lentes producteurs lorsque les consommateurs ne peuvent pas suivre. Les files deviennent bornées ; les émetteurs bloquent ; la source originale de travail ressent la friction.
Diagnostiquer une Cascade
Un groupe d'API fond en fusion lors d'un basculement de base de données de routine. Chronologie :
- 14:00:00 — Opérateur promeut la base de données secondaire. Désavailability prévue : ~ 10 secondes.
- 14:00:08 — La primaire est indisponible. Les requêtes de la couche API commencent à échouer avec des erreurs de connexion de base de données.
- 14:00:08 — La couche API tente de nouveau (configuration par défaut : 5 tentatives, sans recul, 100 ms d'intervalle).
- 14:00:11 — La seconde est promue, accepte de nouvelles connexions.
- 14:00:11 — La couche API ouvre des milliers de nouvelles connexions de base de données simultanément (chaque réplica × chaque demande concurrence × chaque tentative).
- 14:00:13 — La connexion de la nouvelle primaire est épuisée ; les nouvelles connexions sont rejetées.
- 14:00:13-14:05:00 — Les réplicas de la couche API épuisent les pools de connexions, jettent des exceptions, s'écrasent, redémarragent, recommencent.
- 14:05:00 — Opérateur arrête manuellement le trafic de la couche API ; la base de données se stabilise.
- 14:10:00 — La restauration progressive du trafic est terminée. Panne totale : ~ 10 minutes (contre une prévision de ~ 10 secondes).
SERVFAIL DNS : Deux Défauts Composants
Un Postmortem De Forme Réelle
Ce qui suit est une version sanitaire d'un incident réel. Les noms de fournisseurs modifiés, les IPs anonymisées ; la forme, le calendrier et les leçons sont réels.
Résumé
Le site example.com a renvoyé SERVFAIL à partir de tous les résolveurs DNS publics pendant environ 3-4 heures. Les 46 autres zones sur le même maître DNS n'ont pas été affectées. Cause racine : deux défauts composants.
1. Le fournisseur A (un fournisseur de DNS secondaire) a ajouté une nouvelle IP de synchronisation interne qui n'était pas dans la liste autorisée allow-axfr-ips de la primaire.
2. La zone example.com avait un conflit CNAME datant de plusieurs années (RFC-violant) (demo.example.com avait à la fois des enregistrements CNAME et MX/TXT au même étiquette) qui a fait rejeter la zone par le fournisseur A lors d'une nouvelle AXFR.
Chronologie (UTC)
- ~15:00 — Le fournisseur A ajoute la nouvelle IP de synchronisation 198.51.100.42 à son infrastructure
- 15:02 — premier AXFR-out denied pour 198.51.100.42 apparaît dans les journaux DNS primaires (pas d'alerte sur ce signal)
- ~18:00 — la fenêtre de validité SOA est atteinte ; le fournisseur A supprime la zone example.com de la cache
- ~18:30 — SERVFAIL détecté à l'extérieur
- ~19:45 — cause racine identifiée
- 20:00 — 198.51.100.42 ajouté à allow-axfr-ips ; le serveur principal redémarré
- 20:05 — NOTIFY envoyé ; AXFR initié ; zone TROUVE encore SERVFAIL (conflit CNAME)
- 20:07 — check-zone révèle 1 erreur : conflit CNAME sur demo.example.com
- 20:09 — CNAME remplacé par un enregistrement A ; vérification de la zone propre (0 erreurs)
- 20:10 — NOTIFY envoyé ; AXFR termine ; le fournisseur A commence à servir la zone
- 20:11 — dig @8.8.8.8 example.com A retourne l'IP correcte — RÉSOLU
Pourquoi uniquement example.com ?
Toutes les 47 zones partagent le même serveur DNS principal. L'IP AXFR affectée toutes les zones. Mais seulement example.com avait le conflit CNAME et seulement example.com avait besoin d'un AXFR frais au moment où le refus a été appliqué. Les autres zones avaient déjà mis à jour avant le refus ou n'avaient pas encore besoin de le faire.
Défaut latent
Le conflit CNAME à demo.example.com existait depuis des années. Il fonctionnait parce que le serveur principal servait la zone à partir de son base de données (tolérant envers les violations RFC) et que le fournisseur A servait des données obsolètes à partir de la cache avant qu'elle ne soit introduite. Lorsque le fournisseur A a supprimé sa cache et a besoin de données fraîches, la violation est apparue.
Déclencheur
Le fournisseur A a ajouté silencieusement une nouvelle IP de synchronisation. La liste autorisée du serveur principal ne l'incluait pas. AXFR refusé. Trois heures plus tard (SOA expire), le fournisseur A a supprimé la zone. Le défaut latent a surgi lorsque le système a tenté de se rétablir.
Écrire des actions sans faute
Sans faute : Cibler les systèmes, pas les personnes
Une action sans faute nomme quelque chose que le système devrait faire différemment, pas quelque chose que une personne devrait faire différemment. 'Former l'opérateur' est fautif. 'Ajouter une vérification automatique qui attrape cela avant le déploiement' est sans faute.
Les bonnes actions sans faute se regroupent en trois dimensions:
- Prévention : rendre la mauvaise chose plus difficile ou impossible
- Détection : la remarquer plus tôt si cela se produit
- Récupération : limiter les dommages lorsqu'il se produit
Chaque élément devrait nommer (1) la modification du système, (2) l'équipe des propriétés et (3) la dimension à laquelle il sert.
Compartiments qui coulent sans le navire
Emprunté à l'ingénierie navale
Les navires transportent des cloisons étanches : des murs verticaux qui divisent la coque en compartiments. Un compartiment peut être inondé sans faire couler le navire ; un autre peut ne pas affecter le reste.
Les systèmes distribués empruntent la même expression et la même idée.
Pattern de cloison : isoler les ressources par dépendance. Un service qui appelle trois API downstream utilise trois pools de connexions séparés, trois budgets de threads séparés, trois budgets de reprise séparés. Une API downstream lente ou en échec ne peut pas consommer les ressources allouées pour les autres deux.
Sans cloisons : une dépendance lente consomme la file d'attente de threads partagée ; les appels aux autres dépendances bloquent en attente de threads ; le service entier devient non répondu.
Avec cloisons : une dépendance lente consomme sa propre file ; les appels à elle échouent rapidement ; les appels aux autres dépendances continuent normalement ; la zone d'impact reste limitée à la dépendance en échec.
Disjoncteurs à courant
Pattern de disjoncteur : un enveloppe étatique autour d'une dépendance downstream qui suit le taux d'échec. Trois états :
- Fermé (normal) : les appels passent. Les échecs comptabilisés.
- Ouvert (déclencheur) : passé un seuil d'échec (par exemple, 50% d'échecs au cours des 30 dernières secondes), le disjoncteur ouvre. Les appels échouent immédiatement sans tenter la dépendance. Épargne l'appelant du gaspillage de travail ; épargne la dépendance de recevoir la charge tout en étant malade.
- Mi-ouvert (test) : après une période de refroidissement, le disjoncteur autorise une petite fraction d'appels. Si ils réussissent, il ferme à nouveau à la normale. Si ils échouent, il rouvre pour une autre période de refroidissement.
L'insight clé : le disjoncteur à courant empêche les efforts gaspillés pendant les périodes connues comme malades, & donne à la dépendance downstream une chance de se rétablir sans charge continue.
Les cloisons limitent la zone d'impact. Les disjoncteurs empêchent l'explosion de se perpétuer.
Limitation de la zone d'impact
Vos appels de service API utilisent quatre services en aval : Service Utilisateur, Service de recommandation, Service de notification et une API de paiement tierce. L'équipe a entendu dire que 'le Service de recommandation a été un peu flou' et veut s'assurer que lorsque celui-ci échoue, le reste du système reste en bonne santé.
Aujourd'hui, le service utilise une seule file d'attente partagée de 200 threads et une seule file d'attente HTTP partagée. Les quatre services en aval s'affrontent pour ces ressources. Il n'y a pas de briseurs de circuit.
Concevez une revue des modes de panne
Synthèse
Vous avez appris à repérer les SPOFs par inspection, à reconnaître les modèles d'échecs de propagation, à séparer le déclencheur de la défectueuse latente lors de la lecture d'un post-mortem, à rédiger des actions sans faute sur la prévention / détection / récupération et à limiter la portée explosive avec des cloisons + des briseurs de circuit + une dégradation gracieuse.
Appliquez les cinq.
Votre équipe lance un nouveau service search.example.com qui dépend de trois services en aval : un index de recherche principal (index.example.com), un service d'analyse (analytics.example.com) et un service de recommandation (recs.example.com). L'équipe vous demande de diriger une 'revue des modes de panne' avant le lancement.
Où ce cours va à la prochaine
Où ce cours va à la prochaine
Vous pouvez maintenant repérer un SPOF, reconnaître une cascade, lire un post-mortem de manière productive, rédiger des actions sans faute et limiter la portée explosive par conception.
La dernière leçon de ce cours (cs_distsys_observability_and_capacity) enseigne ce qu'il faut mesurer pour découvrir que problème se produit avant que les utilisateurs ne le fassent. Les vérifications d'état de santé, les points de terminaison de version, les quatre signaux d'or au niveau d'un nœud proxy, et comment les décisions de capacité de surcharge sont liées aux données observées.
Leçon complémentaire : geometry_of_failure_modes_and_blast_radius dérive la centralité de betweenness (lequel nœud de graphe est le goulot d'étranglement) et le min-cut (la limite sur le rayon d'explosion).
Bien fait. En avant.