3.3 Systèmes distribués
Vue d’ensemble et motivation
Un système distribué est tout système dont les composants fonctionnent sur plus d’une machine et se coordonnent à travers un réseau. Au moment où vous traversez une frontière de processus à travers un réseau, vous héritez de certaines vérités dures qui n’existent simplement pas à l’intérieur d’un seul processus. Le réseau n’est pas fiable, et sa latence varie. Les messages peuvent être perdus, dupliqués, retardés, ou réordonnés. Les composants distants échouent de leur propre chef. Il n’y a pas d’horloge partagée. Les classiques « erreurs de l’informatique distribuée » (le réseau est fiable, la latence est nulle, la bande passante est infinie, la topologie ne change jamais) nomment exactement les suppositions qui causent les pannes. Votre travail est de concevoir pour ces réalités dès le départ, plutôt que de les redécouvrir pendant un incident.
Pour une grande organisation, la distribution n’est pas optionnelle. Tout système qui sert à l’échelle nationale ou mondiale, joint plusieurs départements, ou a besoin d’une haute disponibilité s’étendra sur de nombreuses machines, centres de données, et souvent régions. Les entreprises exploitent des systèmes de transaction distribués, des pipelines d’événements, et des déploiements multi-régions. Les gouvernements exploitent des intégrations inter-agences où chaque agence possède ses propres systèmes et où personne ne contrôle le tout. Ici, l’écart entre une conception robuste et une fragile apparaît comme des pannes qui font la une, des paiements de prestations manqués, et des conséquences réglementaires. Les techniques de ce chapitre (raisonnement de cohérence, idempotence, nouvelles tentatives avec recul, disjoncteurs, sagas, et observabilité distribuée) sont vos défenses standard.
La partie la plus difficile des systèmes distribués est que les pannes sont partielles et intermittentes. Un programme sur une seule machine fonctionne ou plante. Un système distribué peut fonctionner à moitié : certaines requêtes réussissant, certaines expirant, et certaines perdues silencieusement, tout à la fois. Ce chapitre se concentre sur le raisonnement et les motifs qui permettent à une grande équipe de construire des systèmes qui se dégradent gracieusement et restent compréhensibles sous panne partielle.
Principes clés
- Le réseau n’est pas fiable. Concevez chaque interaction distante en supposant qu’elle peut être lente, échouer, dupliquer, ou réordonner.
- Vous ne pouvez pas avoir une cohérence parfaite et une disponibilité parfaite pendant une partition. Choisissez délibérément par interaction (CAP/PACELC), et rappelez-vous que la latence est un coût même quand il n’y a pas de partition.
- Rendez les opérations idempotentes. Si une opération peut être répétée en toute sécurité, la plupart de la gestion de panne distribuée devient traitable.
- Chaque appel distant a besoin d’un délai d’expiration. Les attentes non bornées transforment une dépendance lente en une panne à l’échelle du système.
- Préférez la cohérence éventuelle là où l’affaire le permet, mais rendez-la explicite. Les utilisateurs et les auditeurs doivent comprendre quand ils pourraient voir des données périmées.
- Isolez les pannes. Les cloisons et les disjoncteurs empêchent un composant défaillant de se propager en cascade à tous les autres.
- Vous ne pouvez pas déboguer ce que vous ne pouvez pas voir. Les flux distribués exigent du traçage corrélé, des métriques, et des journaux à travers chaque saut.
- La « livraison exactement une fois » est un mythe ; le traitement exactement une fois est un exploit d’ingénierie. Concevez pour au-moins-une-fois avec déduplication.
Recommandations
Raisonner sur la cohérence avec CAP et PACELC
Le théorème CAP dit que pendant une partition réseau, un système doit choisir entre la cohérence (chaque lecture voit la dernière écriture) et la disponibilité (chaque requête obtient une réponse). PACELC ajoute un second échange : Else (quand il n’y a pas de partition), vous échangez quand même la Latence contre la Cohérence. Ne tamponnez pas cela comme une étiquette pour tout le système. Décidez-le par opération. Le virement de solde d’une banque a besoin d’une cohérence forte et refusera plutôt que de risquer une double dépense. Un fil social ou un compteur de vues de produit peut accepter la péremption en échange de la disponibilité et de la vitesse. Consignez quel modèle de cohérence chaque flux de données utilise (fort, causal, lecture-de-vos-écritures, ou éventuel) pour que personne ne suppose une garantie que le système ne fournit pas réellement.
Construire ensemble l’idempotence, les délais d’expiration, les nouvelles tentatives, et le recul
Traitez ces quatre techniques comme un seul paquet. Donnez à chaque opération distante un délai d’expiration, pour qu’une dépendance bloquée ne puisse pas bloquer un thread pour toujours. En cas d’échec, réessayez, mais seulement pour les opérations sûres à répéter. Sûr à répéter signifie idempotent : assignez à chaque requête une clé unique et faites en sorte que le récepteur déduplique, pour qu’un « débiter la carte » réessayé ne débite pas deux fois. Espacez vos nouvelles tentatives avec un recul exponentiel et de la gigue, pour éviter une tempête de nouvelles tentatives synchronisée qui transforme un bref accroc en un déni de service auto-infligé. Plafonnez le nombre de nouvelles tentatives et le budget de temps total, parce que réessayer indéfiniment ne fait que déplacer la panne. Sans idempotence, les nouvelles tentatives sont dangereuses. Sans recul, les nouvelles tentatives sont destructrices.
Ajouter des disjoncteurs et des cloisons pour arrêter les cascades
Un disjoncteur surveille les appels à une dépendance et, après un seuil d’échecs, « s’ouvre » : il échoue rapidement pendant une période de refroidissement au lieu d’empiler plus de requêtes sur un service en difficulté, puis se « semi-ouvre » pour tester le rétablissement. Cela arrête la cascade où un service en aval lent épuise les threads de chaque appelant jusqu’à ce que le système entier se bloque. Les cloisons partitionnent les ressources (bassins de threads, bassins de connexions) pour que la saturation dans une dépendance ne puisse pas manger la capacité dont d’autres ont besoin. Associez les deux avec une dégradation gracieuse : quand une dépendance non critique est indisponible, renvoyez des réponses en cache ou par défaut plutôt que de faire échouer toute la requête.
Gérer les transactions distribuées avec des sagas, pas la validation en deux phases
Vous ne pouvez généralement pas tenir une seule transaction ACID (Atomicité, Cohérence, Isolation, Durabilité) à travers plusieurs services ou bases de données. La validation en deux phases distribuée est lente, verrouille des ressources, et réduit la disponibilité. Utilisez plutôt le motif saga. Modélisez une transaction métier comme une séquence de transactions locales, chacune publiant un événement qui déclenche la suivante, avec une action compensatoire pour chaque étape pour l’annuler si une étape ultérieure échoue. Les sagas viennent en deux saveurs. La chorégraphie fait réagir les services aux événements les uns des autres, sans contrôleur central. L’orchestration fait piloter les étapes par un coordinateur central, ce qui est plus facile à raisonner et à surveiller. Les sagas embrassent la cohérence éventuelle : le système passe par des états intermédiaires puis converge. Donc concevez l’expérience utilisateur et la piste d’audit pour tenir compte des états « en cours » et « compensé ».
Traiter l’exactement-une-fois comme au-moins-une-fois plus déduplication
Les courtiers de message ne peuvent pas vraiment garantir la livraison exactement une fois à travers les pannes. Ce qu’eux et vous pouvez atteindre est la livraison au-moins-une-fois avec un traitement idempotent, ce qui produit des effets exactement une fois. Concevez les consommateurs pour gérer les messages dupliqués en toute sécurité, en utilisant des clés d’idempotence ou un journal de messages traités. Connaissez précisément les garanties d’ordonnancement et de livraison de votre courtier. Pour le streaming, utilisez des groupes de consommateurs, des partitions, et une gestion d’offset délibérément, et rendez le retraitement sûr, pour que vous puissiez rejouer un flux après une correction de bug sans corrompre l’état en aval.
Instrumenter les flux distribués de bout en bout
Adoptez les trois piliers de l’observabilité, corrélés à travers les frontières de service. Propagez un ID de trace/corrélation à travers chaque saut, pour pouvoir suivre une seule requête utilisateur à travers tous les services qu’elle touche (traçage distribué). Émettez des métriques structurées (percentiles de latence, taux d’erreur, saturation, débit) par service et par dépendance. Émettez des journaux structurés qui portent l’ID de corrélation. Utilisez tout cela pour fixer des objectifs de niveau de service et pour alerter sur les symptômes que les utilisateurs ressentent réellement, tels que le taux d’erreur et la latence, plutôt que seulement sur la santé de machine individuelle. Dans un système distribué, l’observabilité n’est pas un outillage optionnel. C’est le seul moyen de comprendre le comportement sous panne partielle.
Compromis : avantages et inconvénients
| Technique | Avantages | Inconvénients / coût |
|---|---|---|
| Cohérence forte | Modèle mental simple, pas de lectures périmées | Disponibilité plus basse pendant les partitions, latence plus élevée, coût de coordination |
| Cohérence éventuelle | Haute disponibilité, faible latence, évolutive | Lectures périmées, raisonnement complexe, nécessite une résolution de conflit |
| Nouvelles tentatives avec recul | Traverse les pannes transitoires automatiquement | Amplifie la charge si mal utilisée ; nécessite idempotence et plafonds |
| Disjoncteurs / cloisons | Préviennent la panne en cascade, échouent rapidement | Complexité ajoutée, réglage de seuils, risque de déclenchement prématuré |
| Saga (contre 2PC) | Évolutive, disponible, pas de verrous distribués | Cohérence éventuelle, logique de compensation, plus difficile à raisonner |
Le compromis maître est entre la coordination et l’indépendance. Chaque garantie que vous voulez à travers des machines (cohérence, ordonnancement, exactement-une-fois) coûte de la latence, de la disponibilité, ou de la complexité. Elle exige que les machines s’accordent, et l’accord sur un réseau non fiable est coûteux. La compétence est d’acheter seulement les garanties dont l’affaire a réellement besoin, opération par opération, et de concevoir tout le reste pour une dégradation gracieuse. Sur-acheter la cohérence et vos systèmes deviennent lents et fragiles. La sous-acheter et vous obtenez une corruption de données silencieuse qui surgit comme un échec d’audit des mois plus tard.
Questions à discuter avec votre équipe
Vos motifs de résilience sont-ils livrés comme des valeurs par défaut de plateforme partagées, ou chaque équipe réinvente-t-elle les délais d’expiration et nouvelles tentatives ? Le chapitre traite l’idempotence, les délais d’expiration, les nouvelles tentatives bornées, les disjoncteurs, et le traçage comme les moins chers et les plus fiables quand ils sont construits une fois dans des bibliothèques partagées et des valeurs par défaut de plateforme. Dans une grande organisation, laisser chaque équipe les coder à la main garantit l’incohérence : certains chemins réessayent des opérations non idempotentes, certains n’ont pas de délai d’expiration, certains n’émettent aucun ID de corrélation. Apportez des preuves en auditant un échantillon de services et en comptant combien fixent un délai d’expiration explicite sur chaque appel distant et propagent un ID de trace de bout en bout. Si ce chiffre est bas, la correction est un investissement de plateforme, pas une note de formation. Des valeurs par défaut standard rendent aussi la résilience testable et auditable, ce que les régulateurs en finance et administration publique attendent de plus en plus que vous démontriez.
Vos budgets de délai d’expiration et de nouvelle tentative se composent-ils à travers toute la chaîne d’appels, ou une requête profonde se réessaie-t-elle jusqu’à la panne ? Une seule requête traverse souvent de nombreux sauts, et si chaque couche réessaie indépendamment trois fois avec son propre délai d’expiration, la panne la plus interne se multiplie et l’appelant extérieur attend bien au-delà de toute limite tolérable par l’humain. Fixez un budget de temps total pour la requête orientée utilisateur et divisez-le le long de la chaîne, pour qu’un service interne sache combien peu de temps il lui reste et échoue rapidement plutôt que de réessayer jusqu’à la tempête. Apportez votre graphe de dépendances et une vraie trace, puis additionnez la pire combinaison de délai d’expiration et de nouvelle tentative et comparez-la à ce que l’utilisateur attendra réellement. Le recul exponentiel avec gigue et un plafond sur les tentatives totales empêche un bref accroc de devenir un déni de service auto-infligé. Les chaînes synchrones profondes et bavardes sont l’ennemi ici, donc la réponse peut vous pousser vers des flux asynchrones ou moins de sauts.
Quand avez-vous pour la dernière fois injecté les pannes que votre conception prétend survivre, et qu’est-ce qui s’est cassé que vous n’attendiez pas ? Les motifs de résilience sont des hypothèses jusqu’à ce que vous fassiez échouer le système délibérément : tuer une instance, ajouter de la latence à une dépendance, laisser tomber une fraction de messages, relivrer un lot deux fois. Dans un système distribué, les pannes intéressantes sont partielles et intermittentes, donc un disjoncteur ou une compensation de saga qui semble correct dans le code peut quand même mal se comporter sous un vrai délai-d’expiration-qui-s’est-peut-être-terminé. Apportez les résultats d’une vraie journée de jeu ou d’une exécution d’injection de faute, pas un document de conception, et notez quelles alertes se sont déclenchées, combien de temps le traçage a pris pour localiser la faute, et si une tempête de nouvelle tentative s’est formée. Dans les secteurs régulés, la preuve que vous avez testé la panne fait partie de la démonstration de résilience opérationnelle aux auditeurs. Si vous n’en avez jamais exécuté une, la première expérience appartient à un environnement de test avec un rayon d’impact serré et un interrupteur d’abandon.
Pour chaque flux de données majeur, l’équipe propriétaire peut-elle nommer le modèle de cohérence qu’il fournit, et ce choix correspond-il à ce dont l’affaire a réellement besoin ? CAP et PACELC forcent un choix délibéré par opération, pourtant dans une grande organisation la valeur par défaut est la dérive : un flux qui a commencé éventuellement cohérent pour un compteur à faibles enjeux est réutilisé pour quelque chose qui approuve maintenant des paiements ou accorde un accès, et personne ne réexamine la garantie. Les considérations concurrentes sont réelles, puisque la cohérence forte coûte de la disponibilité pendant une partition et de la latence même quand il n’y en a pas, tandis que la cohérence éventuelle achète de la vitesse au prix de lectures périmées et d’une résolution de conflit que vous devez concevoir. Apportez un catalogue de vos principaux flux de données, chacun étiqueté avec son modèle actuel (fort, causal, lecture-de-vos-écritures, ou éventuel) et la conséquence d’affaires d’une lecture périmée ou perdue, puis cherchez des inadéquations où la garantie est plus forte ou plus faible que ce que les enjeux justifient. En finance d’entreprise et dans les systèmes gouvernementaux de prestations ou d’identité, une lecture éventuellement cohérente derrière une décision faisant autorité est le genre de défaut silencieux qui surgit comme une constatation d’audit ou un refus injustifié des mois plus tard, donc la revue elle-même est une preuve que les auditeurs demanderont à voir.
Comment vos transactions d’affaires multi-services se comportent-elles à mi-chemin, et qui est responsable des compensations qui les défont ? Remplacer la validation en deux phases par des sagas signifie que le système passe par des états intermédiaires visibles, et qu’une étape peut réussir pendant qu’une étape ultérieure échoue et déclenche une action compensatoire qui l’inverse. Pour une grande équipe, cela soulève des questions de propriété difficiles : la chaîne autoriser-débiter-créditer-grand-livre traverse souvent plusieurs équipes, et une compensation qu’une équipe oublie d’implémenter laisse de l’argent ou des registres définitivement incohérents. Pesez la chorégraphie, où les services réagissent aux événements les uns des autres sans contrôleur central et où le flux est difficile à voir, contre l’orchestration, où un coordinateur pilote et surveille les étapes au prix d’un composant à exploiter. Apportez le diagramme d’état pour votre saga la plus importante, la liste des actions compensatoires et leurs propriétaires, et la preuve que les états « en cours » et « compensé » sont gérés à la fois dans l’expérience utilisateur et la piste d’audit. En banque et en gestion de dossiers du secteur public, les régulateurs attendent que vous reconstruisiez exactement ce qui est arrivé à une transaction qui a échoué à mi-chemin, donc un état intermédiaire non modélisé est une lacune de conformité, pas juste un bug.
Vos consommateurs de message survivent-ils à la livraison dupliquée et réordonnée, et pouvez-vous le prouver avant que le courtier ne force la question ? La livraison exactement une fois est un mythe, donc votre vraie garantie est au-moins-une-fois, et un consommateur qui suppose que chaque message arrive une fois et dans l’ordre traitera deux fois le jour où le courtier relivre un lot après un basculement. À travers de nombreuses équipes, le risque se compose, parce qu’un consommateur non idempotent sur un flux partagé peut corrompre l’état en aval dont dépendent d’autres équipes, et la panne est invisible jusqu’à ce qu’une relecture ou une partition réordonne les événements. Le compromis est le coût d’ingénierie des clés d’idempotence, d’un journal de messages traités, et d’une gestion explicite d’offset et de partition, mis en balance avec le coût de la corruption silencieuse. Apportez la liste des consommateurs sur vos flux critiques, notez lesquels dédupliquent et lesquels espèrent simplement, et apportez le résultat d’un vrai test de relivraison ou de relecture plutôt qu’une assurance que ça devrait aller. Pour l’échange de données inter-agences gouvernementales et les pipelines d’événements d’entreprise, la capacité de rejouer un flux en toute sécurité après une correction de bug, sans créer de dossiers ou de frais dupliqués, est à la fois une nécessité opérationnelle et quelque chose que les auditeurs voudront démontré.
Regard sectoriel
Jeune pousse. Avec deux ou trois pièces mobiles et aucune équipe de plateforme, résistez à construire une machinerie distribuée que vous ne pouvez pas doter en personnel. Achetez la résilience là où elle vit déjà dans le SDK que votre fournisseur de paiement ou de messagerie vous donne, et dépensez votre attention rare sur les deux motifs qui préviennent un dommage irréversible : une clé d’idempotence sur chaque appel qui déplace de l’argent ou change un compte, et un délai d’expiration avec nouvelle tentative bornée pour qu’une connexion instable n’agisse jamais deux fois. Gardez le nombre de sauts réseau petit, parce que chaque dépendance synchrone que vous ajoutez est une chose de plus qui peut échouer avant que vous n’ayez quelqu’un d’astreinte pour le remarquer.
Petite entreprise. Vous n’avez probablement pas de spécialiste des systèmes distribués et un budget serré, donc traitez ceci comme une question d’acheter-pas-construire : préférez des files gérées, des bases de données gérées, et des plateformes qui gèrent les nouvelles tentatives, l’ordonnancement, et la déduplication pour vous plutôt qu’une infrastructure que vous devez exploiter. Cadrez votre risque en termes simples, en sachant quelles opérations feraient mal à un client si elles s’exécutaient deux fois ou renvoyaient des données périmées, et activez les fonctionnalités d’idempotence et d’au-moins-une-fois que vos fournisseurs offrent déjà. Évitez de coudre des services ensemble à travers une base de données partagée pour simuler une transaction, puisque cela recrée discrètement le problème distribué le plus difficile sans aucun des outils pour le gérer.
Grande entreprise. Le problème central est la cohérence à travers de nombreuses équipes, donc livrez l’idempotence, les délais d’expiration, les nouvelles tentatives bornées, les disjoncteurs, et le traçage corrélé comme des valeurs par défaut de plateforme partagées plutôt que de laisser chaque groupe les coder à la main. Standardisez comment les modèles de cohérence et les garanties de livraison sont déclarés par flux, exécutez de l’injection de faute et des journées de jeu selon une cadence régulière, et faites en sorte que les budgets de temps totaux se composent à travers des chaînes d’appels profondes pour qu’un service ne puisse pas réessayer la plateforme jusqu’à la panne. Gérez la résilience comme une capacité mesurée avec des objectifs de niveau de service sur des symptômes visibles par l’utilisateur, parce qu’à votre échelle un seul délai d’expiration manquant peut se propager en cascade jusqu’à une panne qui fait la une.
Gouvernement. Les systèmes inter-agences signifient que personne ne possède le tout, donc concevez pour des frontières que vous ne contrôlez pas : des files durables avec livraison au-moins-une-fois, une déduplication sur un ID de message stable, et des ID de corrélation qui circulent à travers les lignes d’agence pour donner aux auditeurs une trace de bout en bout. Les règles d’approvisionnement et de transparence vous poussent à documenter le modèle de cohérence et la garantie de livraison de chaque intégration, et à garder les décisions faisant autorité (identité, éligibilité, prestation) sur des lectures fortement cohérentes plutôt que des points de terminaison en cache. Traitez la preuve de panne testée et l’historique de transaction reconstructible comme des livrables, puisque la résilience opérationnelle et la redevabilité envers le public sont des obligations contractuelles et légales, pas des commodités internes.
Exemples
Jeune pousse. Une petite start-up fintech n’a que deux pièces mobiles qui se parlent à travers le réseau : son application et un fournisseur de paiement tiers. Même à cette taille, elle fait porter à chaque requête de charge une clé d’idempotence et enveloppe l’appel dans une nouvelle tentative avec recul, pour qu’une réponse perdue sur une connexion instable ne facture jamais deux fois un client. Sauter cela semble bon marché le premier jour, mais la première charge dupliquée qui touche un vrai utilisateur coûte un incendie de support, un remboursement, et une brèche de confiance que la jeune entreprise ne peut pas se permettre.
Grande entreprise. Une plateforme de covoiturage mondiale traite les paiements de trajet à travers une saga : autoriser la carte, débiter le passager, créditer le conducteur, enregistrer l’écriture de grand livre, chacune une transaction locale avec une inversion compensatoire. Chaque étape porte une clé d’idempotence, donc les nouvelles tentatives après un délai d’expiration réseau ne facturent jamais deux fois. Les appels au service de notation de fraude se trouvent derrière un disjoncteur ; quand il se dégrade au pic, le disjoncteur s’ouvre et les déclenchements se rabattent sur un score conservateur au lieu de bloquer chaque trajet. Quand un client conteste un trajet, le traçage distribué permet aux ingénieurs de le suivre à travers une douzaine de services en secondes.
Gouvernement. Un service d’identité national est utilisé par de nombreuses agences pour la vérification. Il offre une lecture fortement cohérente pour les vérifications de statut faisant autorité (vous ne devez pas approuver une prestation contre des données d’identité périmées), plus un point de terminaison en cache et éventuellement cohérent pour les recherches à fort volume et non critiques. L’échange de données inter-agences fonctionne sur une file de message durable avec livraison au-moins-une-fois, et le consommateur de chaque agence déduplique sur un ID de message, pour qu’un enregistrement relivré ne crée pas un dossier dupliqué. Les ID de corrélation circulent à travers les frontières d’agence, donnant aux auditeurs une trace de bout en bout de comment les données d’un citoyen se sont déplacées entre départements.
Argumentaire économique : motivations, retour sur investissement et coût total de possession
La discipline des systèmes distribués s’achète à bas prix et son absence se paie catastrophiquement. Le coût d’adoption est le temps d’ingénierie pour construire l’idempotence, les délais d’expiration, les nouvelles tentatives, les disjoncteurs, et le traçage dans des bibliothèques partagées et des valeurs par défaut de plateforme. C’est un investissement modeste et principalement ponctuel qui bénéficie ensuite à chaque équipe. Le coût de ne pas l’adopter se mesure en pannes majeures : un seul délai d’expiration manquant qui se propage en cascade en une panne de plateforme complète, un chemin de paiement non idempotent qui facture deux fois des milliers de clients, ou une transaction distribuée sans saga qui laisse des données définitivement incohérentes. Chacune de celles-ci est un incident qui fait la une avec un coût direct de revenu, de remédiation, et réputationnel, et dans les secteurs régulés, des amendes.
Cadrez le dossier pour la direction autour de la disponibilité et du rayon d’impact. Les motifs de résilience réduisent directement à la fois la fréquence et la durée des incidents sévères, les métriques que les cadres suivent déjà comme le temps de disponibilité et le temps moyen de récupération. L’observabilité distribuée est le plus grand levier unique sur le MTTR : les équipes avec du traçage corrélé résolvent les incidents inter-services en une fraction du temps. Parce que ces capacités sont mieux livrées comme des valeurs par défaut de plateforme partagées, leur coût marginal par équipe est bas et leur gain à l’échelle de l’organisation se compose. L’argument du CTP est simple : construire la résilience dès le départ est une fraction du coût de la rétro-adapter après la panne qui force la question.
Anti-patterns et pièges
- Pas de délais d’expiration. Une seule dépendance bloquée épuise chaque thread et fait tomber le système entier.
- Réessayer des opérations non idempotentes. Des effets secondaires dupliqués : doubles charges, enregistrements dupliqués, e-mails doublés.
- Tempêtes de nouvelles tentatives. Des nouvelles tentatives synchronisées sans recul ni gigue qui amplifient un petit accroc en panne.
- Supposer une livraison exactement une fois. Construire des consommateurs qui se cassent sur les messages dupliqués que le courtier livrera éventuellement.
- Transactions distribuées via base de données partagée. Coupler des services à travers une base de données pour simuler ACID, recréant un monolithe distribué.
- Ignorer la panne partielle. Du code qui suppose qu’un appel distant réussit entièrement ou échoue entièrement, sans gestion pour « expiré mais peut-être terminé ».
- Pas d’ID de corrélation. Déboguer un incident inter-services en faisant du grep dans des journaux sans rapport sur dix machines.
- Chaînes d’appels synchrones bavardes. Des graphes de dépendances synchrones profonds où un seul saut lent bloque la requête entière.
Modèle de maturité
- Niveau 1 (Initier) : Les appels distants sont traités comme des appels locaux. Les délais d’expiration manquent ou sont naïfs, les nouvelles tentatives sont absentes ou imprudentes, et les pannes se propagent en cascade à travers le système. Il n’y a pas de vue partagée de la cohérence ou de la livraison, et déboguer un incident inter-services signifie fouiller dans les journaux machine par machine après coup.
- Niveau 2 (Développer) : Certaines équipes ajoutent des délais d’expiration et des nouvelles tentatives de base et un peu d’idempotence, mais les pratiques sont incohérentes de service à service. Les journaux sont centralisés mais non corrélés, donc tracer une requête à travers les sauts est manuel. Les transactions distribuées sont espérées fonctionner plutôt que modélisées, et les garanties de cohérence vivent dans les têtes d’ingénieurs individuels.
- Niveau 3 (Standardiser) : L’idempotence, les nouvelles tentatives bornées, le recul avec gigue, les disjoncteurs, et les cloisons sont standard à travers l’organisation via des bibliothèques partagées. Les sagas avec actions compensatoires gèrent les transactions multi-services, le traçage distribué avec des ID de corrélation est en place, et chaque flux de données majeur documente son modèle de cohérence et sa garantie de livraison. Les règles sont écrites et imposées à l’échelle de l’organisation plutôt que laissées à chaque équipe.
- Niveau 4 (Gérer) : La résilience est mesurée par rapport à des références, pas seulement présente. Vous suivez le taux d’erreur, les percentiles de latence, la saturation, et le débit par service et dépendance, surveillez les ratios de nouvelle tentative et les taux d’ouverture de disjoncteur, et fixez des objectifs de niveau de service sur des symptômes visibles par l’utilisateur. Les budgets de temps totaux sont vérifiés pour se composer à travers les chaînes d’appels, le temps moyen de récupération pour les incidents inter-services est une métrique surveillée, et les résultats d’injection de faute et de journée de jeu alimentent les chiffres qui conditionnent chaque changement.
- Niveau 5 (Orchestrer) : La résilience est la valeur par défaut de plateforme continuellement améliorée, intégrée à travers toute l’organisation et adaptative aux conditions. L’injection de faute s’exécute couramment en production avec des rayons d’impact serrés, les systèmes se dégradent gracieusement par conception, et les choix de cohérence et de livraison sont réexaminés à mesure que la charge et les enjeux d’affaires changent. Les métriques du niveau 4 pilotent des réponses automatisées et une évolution architecturale régulière, si bien que le parc distribué devient plus robuste avec chaque incident plutôt que de simplement le survivre.
Pistes de réflexion
- Lesquelles de vos opérations critiques sont véritablement idempotentes aujourd’hui, et lesquelles ne le sont discrètement pas ?
- Pour chaque flux de données majeur, votre équipe peut-elle énoncer le modèle de cohérence et la garantie de livraison de mémoire ?
- Où un disjoncteur aurait-il prévenu votre dernière panne en cascade ?
- Combien de temps faut-il actuellement pour tracer une seule requête en échec à travers tous les services qu’elle touche ?
- Lesquelles de vos « transactions distribuées » reposent en réalité sur la chance, et lesquelles sont de vraies sagas avec compensations ?
- Si votre courtier de messages relivrait chaque message deux fois pendant une heure, qu’est-ce qui se casserait ?
Points clés à retenir
- Supposez que le réseau n’est pas fiable et que les pannes sont partielles ; concevez chaque interaction distante pour la lenteur, la perte, la duplication, et le réordonnancement.
- Décidez cohérence contre disponibilité par opération en utilisant CAP/PACELC ; documentez le modèle que chaque flux fournit.
- L’idempotence, les délais d’expiration, les nouvelles tentatives bornées, et le recul-avec-gigue sont un seul paquet ; n’adoptez jamais les nouvelles tentatives sans les trois autres.
- Les disjoncteurs et les cloisons contiennent les pannes ; les sagas avec compensations remplacent les transactions distribuées impraticables.
- Traitez la livraison comme au-moins-une-fois et rendez le traitement idempotent pour atteindre des effets exactement une fois.
- Le traçage corrélé, les métriques, et les journaux sont le seul moyen de comprendre et d’exploiter les flux distribués.
Références et lectures complémentaires
- Martin Kleppmann, Designing Data-Intensive Applications
- Andrew Tanenbaum et Maarten van Steen, Distributed Systems: Principles and Paradigms
- Michael Nygard, Release It!: Design and Deploy Production-Ready Software
- Sam Newman, Building Microservices
- Chris Richardson, Microservices Patterns (sagas, messagerie transactionnelle)
- Eric Brewer, « CAP Twelve Years Later » et Daniel Abadi sur PACELC
- Leslie Lamport, « Time, Clocks, and the Ordering of Events in a Distributed System »
- Cindy Sridharan, Distributed Systems Observability
- La notion d’antifragilité de Nassim Nicholas Taleb (telle qu’appliquée par la littérature d’ingénierie de résilience)