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 Requestsavec un en-têteRetry-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.