Aller au contenu

Impact sur les architectures distribuées

Les fallacies of distributed computing — chaque illusion ancrée dans la réalité réseau des chapitres précédents.


Le réseau n'est pas une abstraction transparente

Les six chapitres précédents ont couvert les fondations réseau : modèle en couches, commutation, routage, transport, protocoles applicatifs et performance. Ce dernier chapitre fait la synthèse en montrant comment ces réalités physiques impactent la conception des systèmes distribués.

Peter Deutsch et ses collegues chez Sun Microsystems ont formule en 1994 les huit fallacies of distributed computing — huit hypothèses fausses que les développeurs font implicitement quand ils concoivent des systèmes distribués. Trente ans plus tard, chacune de ces fallacies reste un piege actif.


Les huit fallacies

1. The network is reliable

C'est la fallacy la plus dangereuse. On l'a vu au chapitre 02 : un cable se debranche, un switch reconverge après une boucle STP, un routeur redondant prend le relai avec quelques secondes de perte. Au chapitre 03 : une convergence OSPF prend 1 a 5 secondes, une convergence BGP prend des minutes. Au chapitre 06 : un buffer de routeur débordé et des paquets sont jetes.

Le réseau va tomber. Pas si, mais quand. Les études de Google et Microsoft sur leurs propres datacenters montrent que les pannes réseau sont quotidiennes à l'échelle d'un grand cluster. La question n'est pas "comment empêcher les pannes réseau" mais "comment concevoir des systèmes qui fonctionnent malgre les pannes réseau".

2. Latency is zero

On l'a quantifie au chapitre 06 : 0.5 ms dans un datacenter, 5 ms entre zones, 50-100 ms entre continents. Chaque appel réseau ajoute au minimum un RTT de latence. Un design qui fait 20 appels séquentiels a un service distant paie 20 RTT de latence incompressible. C'est la différence entre un appel de méthode locale (nanosecondes) et un appel réseau (millisecondes) — un facteur de 10^6.

3. Bandwidth is infinite

La bande passante est finie et partagee. On l'a vu au chapitre 06 : la sursouscription des switches (20 ports 1G vers 1 uplink 10G) crée de la congestion. Un service qui transfere des GB de données entre ses nœuds sature les liens et dégradé tous les autres services partageant le même réseau. Le cas typique : une réplication de base de données ou un job de batch qui sature un lien WAN inter-datacenter et dégradé le trafic applicatif. La solution passe par le traffic shaping (QoS, chapitre 06) ou par la compression et la pagination des transferts.

4. The network is secure

Chaque couche a ses vulnérabilités. Couche 2 : ARP spoofing (chapitre 02). Couche 3 : BGP hijacking (chapitre 03). Couche 4 : SYN flood (chapitre 04). Couche 7 : injection, XSS. Le chiffrement TLS (chapitre 05) protégé la confidentialite et l'intégrité, mais pas la disponibilité. Le modèle zero trust part du principe que le réseau interne est aussi hostile que le réseau externe — chaque appel inter-service est authentifie et chiffre, même à l'intérieur du datacenter.

5. Topology doesn't change

La topologie change constamment. Les routeurs tombent et reconvergent (chapitre 03). Les conteneurs sont redeployes sur d'autres nœuds. Les instances cloud sont remplacees par l'autoscaler. Les adresses IP changent. DNS (chapitre 05) et le service discovery sont les mécanismes qui masquent ces changements — mais ils ont leurs propres latences et coherences.

6. There is one administrator

Un paquet qui traverse Internet passe par une dizaine d'AS (chapitre 03), chacun géré par une organisation différente avec ses propres politiques, ses propres maintenances, ses propres incidents. Dans un cloud multi-provider, les équipes réseau du cloud provider, les équipes infra internes et les équipes applicatives ont des perimetres de responsabilité différents et des informations partielles.

7. Transport cost is zero

L'encapsulation (chapitre 01) a un coût : chaque paquet porte des dizaines d'octets d'overhead. La serialisation a un coût CPU. Le chiffrement TLS (chapitre 05) consomme du CPU. Les connexions TCP (chapitre 04) consomment de la mémoire et des file descriptors. Et au-delà du coût technique, le trafic réseau entre regions cloud est facture — et les factures peuvent être énormes. Un service qui répliqué 1 TB de données entre US-East et EU-West paie des centaines de dollars par mois en egress fees.

8. The network is homogeneous

Les réseaux réels melangent des technologies hétérogènes : Ethernet 1G, 10G, 25G, 100G. Wi-Fi. 4G/5G. VPN. Overlay networks. Chaque technologie a son MTU (chapitre 06), sa latence, sa fiabilité. Un service accessible depuis un datacenter fibre et depuis un téléphone 4G en zone rurale doit gérer des conditions réseau radicalement différentes. Les techniques de graceful dégradation (réduire la qualité d'image, désactiver les fonctionnalités non essentielles) permettent de maintenir un service utilisable même sur les réseaux les plus degrades.


Synthèse : chaque fallacy et ses conséquences

Fallacy Réalité réseau Conséquence architecture
Le réseau est fiable Pannes L1-L3, convergence, buffer overflow Retries, circuit breakers, idempotence
La latence est nulle 0.5 ms intra-DC, 150 ms intercontinental Batching, caching, async, choix de topologie
La bande passante est infinie Liens partages, sursouscription, congestion Compression, pagination, backpressure
Le réseau est sur ARP spoofing, BGP hijack, man-in-the-middle TLS partout, zero trust, defense en profondeur
La topologie ne change pas Reconvergence OSPF/BGP, autoscaling, redeploiement Service discovery, DNS, health checks
Il y a un seul admin Multi-AS, multi-cloud, multi-équipe Observabilité end-to-end, contrats SLA
Le transport est gratuit Overhead, CPU TLS, facturation inter-region Optimisation des payloads, choix de region
Le réseau est homogène MTU varies, latences variees, débits varies Graceful dégradation, adaptive quality

Les partitions réseau

Une partition réseau (network partition) se produit quand un groupe de nœuds ne peut plus communiquer avec un autre groupe, alors que les deux groupes continuent de fonctionner individuellement. Physiquement, c'est un lien coupe (chapitre 02), une route qui disparait (chapitre 03), un firewall mal configuré, ou un switch sature qui jette des paquets (chapitre 06).

Partition vs panne

La distinction est cruciale :

  • Panne : un nœud est mort. Les autres le detectent (après un timeout) et continuent sans lui.
  • Partition : les nœuds sont vivants mais ne se voient plus. Chaque côté croit que l'autre est mort. Si chaque côté continue à accepter des écritures, les données divergent.

C'est le scenario du split brain. Un cluster de base de données avec deux nœuds qui ne se voient plus peut elire deux leaders — chacun accepte des écritures différentes. Quand la partition se résout, les données sont inconsistantes et la reconciliation est soit automatique (CRDTs), soit manuelle (et douloureuse).

Les partitions partielles

Les partitions ne sont pas toujours totales. Une partition partielle se produit quand le nœud A peut parler a B, B peut parler a C, mais A ne peut pas parler a C. Ce scenario est plus frequent qu'on ne le croit — un switch defaillant, un cable avec des erreurs intermittentes, ou un firewall qui bloque un sous-ensemble de ports.

Les partitions asymetriques sont encore plus vicieuses : A peut envoyer a B, mais B ne peut pas répondre a A. TCP détecté ce cas (le handshake échoué), mais UDP ne le détecté pas — les messages partent dans le vide sans erreur.

graph LR
    A["Noeud A"] --"OK"--> B["Noeud B"]
    B --"OK"--> C["Noeud C"]
    A --"BLOQUE"--> C
    C --"BLOQUE"--> A

Les algorithmes de consensus (Raft, Paxos) sont conçus pour gérer ces cas, mais ils supposent que les partitions finissent par se résoudre. Une partition permanente nécessité une intervention humaine.

Le théorème CAP — aperçu

Le théorème CAP (Brewer, 2000) formalise un compromis fondamental : en présence d'une partition réseau (P), un système distribué doit choisir entre la cohérence (C — tous les nœuds voient les mêmes données) et la disponibilité (A — chaque requête reçoit une réponse).

Choix Comportement pendant une partition Exemples
CP Refuse les requêtes pour maintenir la cohérence ZooKeeper, etcd, Consul
AP Répond avec des données potentiellement stale Cassandra, DynamoDB (mode eventual)

Le théorème CAP sera traite en détail dans le chapitre sur le stockage (06-connecter-stocker). Ici, l'essentiel est de comprendre que la partition réseau n'est pas un cas théorique — c'est une réalité opérationnelle que chaque système distribué doit anticiper.

Note

Kyle Kingsbury (projet Jepsen) a montre que la plupart des bases de données distribuées ne respectent pas leurs propres garanties de cohérence pendant les partitions. Tester le comportement de son système sous partition (chaos engineering) est le seul moyen de savoir ce qui se passe reellement.

Détecter les partitions

Détecter une partition réseau est difficile. Du point de vue d'un nœud isole, une partition est indistinguable d'un nœud distant en panne. Les mécanismes de détection reposent sur des timeouts et des quorums :

  • Heartbeat timeout : si un nœud ne reçoit pas de heartbeat d'un pair pendant N secondes, il le considéré mort. Mais le pair est peut-être vivant et isole par une partition. Un timeout trop court généré des faux positifs (nœuds declares morts a tort). Un timeout trop long retarde la détection.
  • Quorum : un nœud qui ne peut joindre la majorité du cluster se considéré comme partitionne et cesse d'accepter des écritures. C'est le mécanisme utilisé par Raft et Paxos. Le nœud isole sait qu'il est du mauvais côté de la partition.
  • Fencing : quand un nouveau leader est elu, l'ancien leader doit être empêché d'écrire (fence). Sans fencing, le split brain persiste même après la détection.

Concevoir pour l'échec réseau

Idempotence

Si le réseau peut perdre un acquittement (le serveur a traite la requête mais la réponse s'est perdue), le client va retenter. Si l'opération n'est pas idempotente, le retry provoque un doublon. Chaque opération qui traverse le réseau doit être idempotente — ou protégée par un token d'idempotence.

POST /payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

→ Le serveur stocke le resultat associe a la cle
→ En cas de retry, il retourne le resultat stocke au lieu de re-executer

Timeouts et retries

Un timeout trop court généré des faux positifs — le service est vivant mais lent. Un timeout trop long gaspille des ressources en attendant un service mort.

Type de timeout Valeur typique Raison
Connect timeout 1-3 secondes Si le serveur ne répond pas au SYN en 3s, il est probablement injoignable
Read timeout 5-30 secondes Dépend du temps de traitement attendu
Idle timeout 60-300 secondes Libérer les connexions inutilisees

Les retries doivent être exponentiels avec jitter : chaque retry attend plus longtemps que le précédent, avec une composante aléatoire pour éviter que tous les clients retentent en même temps (thundering herd).

La formule classique : delai = min(base * 2^tentative + random(0, jitter), max_delai). Avec base=100ms, jitter=100ms, max_delai=30s, les trois premières tentatives espacent les retries de ~200ms, ~400ms, ~800ms. Sans jitter, 1000 clients qui échouent simultanément retentent simultanément — transformant une panne transitoire en surchargé permanente.

Circuit breaker

Quand un service distant est en panne, continuer a envoyer des requêtes qui vont timeout est un gaspillage de ressources et une source de cascading failure. Le pattern circuit breaker coupe les appels après un seuil d'échecs et les reouvre périodiquement pour tester si le service est revenu.

graph LR
    C["Closed<br>(normal)"] --"N echecs consecutifs"--> O["Open<br>(court-circuite)"]
    O --"apres timeout"--> HO["Half-Open<br>(test)"]
    HO --"succes"--> C
    HO --"echec"--> O

Backpressure

Quand un service est submerge, il doit le signaler a ses appelants plutôt que de s'ecrouler silencieusement. La backpressure est le mécanisme par lequel un système en aval ralentit les systèmes en amont :

  • TCP : la fenêtre de reception (chapitre 04) est un mécanisme de backpressure natif
  • HTTP : retourner un 429 Too Many Requests avec un en-tête Retry-After
  • Messaging : les consumers qui ralentissent font grossir la queue — le système de messaging peut alerter ou rejeter les producteurs

Communication asynchrone

Le moyen le plus efficace de se protéger de l'échec réseau est de ne pas en dépendre pour chaque requête. La communication asynchrone via des files de messages (Kafka, RabbitMQ, NATS) découplé l'émetteur du récepteur :

  • L'émetteur envoie un message et continue sans attendre de réponse
  • Le récepteur traite le message quand il est disponible
  • Si le récepteur est en panne, les messages s'accumulent dans la file et seront traites a son retour

Le coût : la consistance n'est plus immédiate mais eventuelle (eventual consistency). C'est un compromis que de nombreux systèmes peuvent accepter.

Le pattern outbox combine le meilleur des deux mondes : l'application écrit dans sa base de données et dans une table "outbox" dans la même transaction. Un processus séparé lit la table outbox et publie les messages dans la file. La consistance locale est garantie par la transaction, et la livraison asynchrone découplé l'émetteur du réseau.


Observabilité réseau dans les systèmes distribués

On ne peut pas concevoir pour l'échec réseau sans le détecter. L'observabilité réseau est la capacité a comprendre ce qui se passe dans le réseau à partir de données collectees en continu.

Les trois piliers appliques au réseau

Métriques : taux de retransmission TCP, RTT entre services, nombre de connexions par état, bande passante utilisée par lien. Ces métriques se collectent via les compteurs du noyau (/proc/net/snmp, /proc/net/netstat) ou via un service mesh qui instrumente chaque appel.

Traces distribuées : chaque requête qui traverse le réseau porte un trace ID. On peut reconstituer le chemin complet d'une requête à travers les services et mesurer le temps passe dans chaque saut réseau. Les outils comme Jaeger ou Tempo visualisent ces traces.

Logs : les logs de connexion (timeout, reset, refused) sont souvent la première indication d'un problème réseau. Mais ils sont produits côté application — le réseau lui-même ne logue rien par défaut. Les flow logs (VPC Flow Logs en AWS/GCP) capturent le trafic au niveau IP et permettent d'analyser les patterns de communication après coup.

Chaos engineering réseau

Tester le comportement du système sous partition ou dégradation réseau est le seul moyen de valider les mécanismes de résilience. Les outils courants :

Outil Type de perturbation Niveau
tc (Linux) Latence, perte, corruption, reordering Interface réseau
Toxiproxy Latence, timeout, perte entre services Proxy applicatif
Chaos Monkey Arrêt aléatoire d'instances Infrastructure
Istio fault inject Latence, erreurs HTTP entre services mesh Service mesh
Pumba Perturbation réseau sur conteneurs Docker Container

Warning

Le chaos engineering sans observabilité est de la destruction aveugle. Avant d'injecter des pannes, il faut avoir les métriques et les alertes en place pour détecter l'impact. L'objectif n'est pas de casser des choses — c'est de vérifier que les mécanismes de résilience fonctionnent comme prévu.


Le réseau comme contrainte architecturale

Chaque décision architecturale doit être évaluée à travers le prisme du réseau :

Monolithe vs microservices : chaque découpé en microservice transforme un appel de méthode local (nanosecondes, fiable) en un appel réseau (millisecondes, faillible). Le gain en découpage organisationnel se paie en complexité réseau. Sam Newman le formule bien : "don't distribute for the sake of distributing."

Region et zone : placer des services dans des regions différentes ajoute 10-100 ms de latence par appel. La réplication inter-region pour la disponibilité a un coût en latence et en cohérence. Le choix entre active-passive (une seule region sert le trafic) et active-active (plusieurs regions servent simultanément) dépend directement des contraintes de latence et de cohérence que le réseau impose.

Synchrone vs asynchrone : un appel synchrone couple l'appelant à la disponibilité de l'appelé. Un appel asynchrone découplé mais ajoute de la complexité (ordering, exactly-once, dead letters).

Caching : mettre des données en cache localement réduit les appels réseau mais introduit des problèmes de cohérence. Le TTL du cache est un compromis entre fraicheur et performance.

Service mesh : un service mesh (Istio, Linkerd) externalise la gestion du réseau (retries, circuit breakers, mTLS, observabilité) hors du code applicatif. Il ajoute un sidecar proxy devant chaque service, ce qui ajoute de la latence (~1 ms) mais uniformise la résilience réseau. Le compromis : complexité opérationnelle vs robustesse.


Checklist de l'architecte face au réseau

Avant de valider une architecture distribuée, vérifier chaque point :

Question Mauvaise réponse Bonne réponse
Que se passe-t-il si le réseau est coupe ? "Ca n'arrive jamais" "On bascule en mode dégradé en X secondes"
Combien d'appels réseau par requête utilisateur ? "Je ne sais pas" "N appels, dont M en parallèle, latence totale ~Xms"
Les opérations sont-elles idempotentes ? "On verra en production" "Oui, avec un token d'idempotence sur les écritures"
Quel est le timeout de chaque appel ? "Le défaut de la librairie" "Configuré a 2x le p99 observe"
Comment détecté-t-on une partition ? "Pas prévu" "Health checks + circuit breaker + alerting"
Quel est le MTU effectif ? "1500 je suppose" "Vérifié, 1450 à cause du tunnel VXLAN"
Le DNS est-il cache correctement ? "Le framework géré" "TTL vérifié, cache invalide en X secondes"

Cette checklist n'est pas exhaustive, mais elle couvre les erreurs les plus fréquentes.

Tip

Avant chaque design review, parcourir les huit fallacies et vérifier que le design les traite explicitement. C'est un exercice de 15 minutes qui evite des semaines de debugging en production.

Les chapitres suivants de ce parcours architecture approfondiront chacun de ces compromis. Les fondations réseau couvertes ici fournissent le vocabulaire et l'intuition nécessaires pour les aborder avec lucidite.


Chapitre suivant : Évolution des architectures — du mainframe au cloud-native.