Aller au contenu
English
Cloud high

Synchrone, asynchrone, eventual consistency : les patterns cloud

17 min de lecture

Le cloud impose une rupture conceptuelle par rapport aux applications monolithiques : les services communiquent à travers un réseau qui peut tomber, ralentir, perdre des messages. Cette réalité oblige à choisir entre communication synchrone (j'attends la réponse) et asynchrone (je publie un message, je continue). Elle force aussi à comprendre le CAP theorem correctement : la tolérance aux partitions n'est pas un choix sur un système distribué, et l'arbitrage entre cohérence forte et disponibilité ne se pose que pendant une partition. Cette page explique les patterns, situe l'eventual consistency et les cas où elle ne suffit pas, et détaille le pattern Saga pour les transactions distribuées qui ne tiennent plus dans une transaction ACID.

  • La distinction synchrone vs asynchrone et leurs compromis pratiques
  • Le CAP theorem appliqué aux bases de données cloud (DynamoDB, Spanner, Cosmos)
  • L'eventual consistency : ce que c'est, ses cas d'usage, ses pièges
  • Le pattern Saga pour les transactions distribuées sans 2PC
  • Comment choisir synchrone ou asynchrone selon le scénario

Prérequis : avoir compris loose coupling et stateless design. Si besoin, lisez d'abord Loose coupling et stateless design.

1. Synchrone vs asynchrone, les deux modes de communication

Section intitulée « 1. Synchrone vs asynchrone, les deux modes de communication »

Le service A appelle le service B et attend la réponse avant de continuer son traitement. C'est le modèle REST classique, gRPC, et la plupart des appels HTTP.

Avantages :

  • Simple à raisonner : la logique se lit linéairement, comme un appel de fonction.
  • Erreur immédiatement visible : si B est down, A reçoit une erreur tout de suite.
  • Pas d'infrastructure additionnelle : juste deux services et un réseau.

Inconvénients :

  • Couplage temporel fort : A et B doivent être disponibles en même temps.
  • Latence cumulative : si A appelle B qui appelle C, la latence totale est la somme.
  • Saturation en cascade : si B ralentit, A ralentit aussi, tous les threads d'A se bloquent.

Le service A publie un message dans une file (queue) ou un événement dans un bus, puis continue son traitement. Le service B consomme le message plus tard, à son rythme.

Avantages :

  • Découplage temporel : B peut être down sans bloquer A.
  • Résilience : la file absorbe les pics de charge, B traite à son rythme.
  • Scaling indépendant : A et B scalent selon leurs propres profils.

Inconvénients :

  • Plus complexe à raisonner : la logique n'est plus linéaire, il faut suivre les flux d'événements.
  • Erreur différée : si le traitement échoue, A ne le sait pas immédiatement.
  • Infrastructure additionnelle : il faut une file (RabbitMQ, SQS, Service Bus, Pub/Sub) ou un bus (Kafka, EventBridge).
CritèreSynchroneAsynchrone
Couplage temporelFortFaible
Latence perçue utilisateurImmédiateDifférée
Tolérance aux pannesFaibleÉlevée
ComplexitéFaibleMoyenne à élevée
Cas d'usageLecture de données, validation immédiateTraitement long, notifications, intégrations
Patterns associésCircuit breaker, retry, timeoutSaga, event sourcing, CQRS
  • L'utilisateur attend la réponse dans son interface (lecture, validation).
  • La logique métier exige un retour immédiat (paiement avec confirmation).
  • Le service appelé est rapide (latence < 100 ms p95) et fiable (SLA > 99,9 %).
  • Le traitement est long (> 1 seconde) et l'utilisateur n'a pas besoin de la réponse immédiate.
  • La charge est variable et il faut absorber les pics (file = buffer).
  • Plusieurs services consomment le même événement (architecture event-driven).
  • La résilience est critique : si B est down, A doit continuer.

2. CAP : faut-il vraiment choisir deux propriétés sur trois ?

Section intitulée « 2. CAP : faut-il vraiment choisir deux propriétés sur trois ? »

Non, et c'est la vulgarisation la plus répandue du théorème

Section intitulée « Non, et c'est la vulgarisation la plus répandue du théorème »

La formule « choisissez 2 sur 3 » est fausse, ou du moins trompeuse, et elle mène à des décisions d'architecture absurdes. Le CAP theorem (Eric Brewer, 2000, démontré formellement par Gilbert et Lynch en 2002) porte sur les trois propriétés suivantes.

LettrePropriétéDéfinition
CConsistency (cohérence forte)Toutes les lectures retournent la donnée la plus récente écrite
AAvailabilityToute requête reçoit une réponse (succès ou erreur métier), pas de timeout
PPartition toleranceLe système continue de fonctionner si le réseau se partitionne

La partition n'est pas une option, c'est un événement. Vous ne « choisissez » pas P : dès que votre système est distribué, le réseau finit par se couper, par une panne de zone ou un lien inter-région rompu. Renoncer à P reviendrait à renoncer à la distribution elle-même.

L'énoncé utile est donc le suivant : quand une partition survient, le système doit trancher entre rester cohérent en refusant de servir une partie des requêtes (CP) et rester disponible en acceptant de servir des données potentiellement obsolètes (AP). Le reste du temps, en l'absence de partition, un système peut parfaitement offrir cohérence et disponibilité : c'est même le cas nominal. C'est ce que formalise l'extension PACELC, qui ajoute qu'en dehors des partitions (Else) l'arbitrage se déplace entre latence et cohérence.

Quand un système distribué subit une partition réseau, deux choix s'offrent :

Choix CP : refuser les écritures sur le côté qui ne peut pas se synchroniser, pour garantir que toutes les lectures voient la donnée à jour. Le service est partiellement indisponible mais cohérent.

Choix AP : accepter les écritures partout, accepter que les lectures puissent retourner des données légèrement obsolètes. Le service reste disponible mais cohérence éventuelle.

Positionnement des bases de données cloud sur CAP

Section intitulée « Positionnement des bases de données cloud sur CAP »
BasePositionnementCompromis
DynamoDB, table régionaleAP, avec lectures fortement cohérentes en optioncohérence éventuelle par défaut, fortement cohérente à la demande et à surcoût
DynamoDB, global tablesMREC par défaut, MRSC au choixle mode se fixe à la création et ne se change plus ensuite
Cosmos DBConfigurable (5 niveaux de cohérence)Permet de choisir le compromis selon collection
Cloud Spanner (GCP)CP avec haute dispoCohérence forte globale via une horloge atomique distribuée propriétaire, latence supérieure
Aurora Multi-RegionAP avec consistency configurableDisponibilité maximale, lectures locales rapides
MongoDB AtlasConfigurableRead concerns du local au linearizable

Une instance de base de données isolée n'a pas sa place dans ce tableau, et c'est une confusion fréquente. CAP décrit le comportement d'un système distribué face à une partition : un PostgreSQL mono-instance n'est pas partitionnable, il est simplement indisponible quand il tombe. Le classer en « CA » donne l'illusion d'un compromis avantageux là où il n'y a qu'un point de défaillance unique. La question CAP ne se pose qu'à partir du moment où vous répliquez.

Spanner est le cas le plus intéressant : Google a investi dans une horloge atomique distribuée (technologie propriétaire baptisée TrueTime) pour atteindre une cohérence forte tout en restant globalement distribué, au prix d'une latence supérieure par écriture (50–100 ms vs 5 ms en local). C'est un compromis ingénierie remarquable mais inadapté aux workloads très haute fréquence.

L'eventual consistency (cohérence éventuelle) signifie que les lectures peuvent retourner une donnée légèrement obsolète pendant un court délai (typiquement quelques millisecondes à quelques secondes), mais que toutes les répliques convergent in fine vers la même valeur.

Si un utilisateur écrit une donnée à 14h00m00s, une lecture à 14h00m01s peut retourner l'ancienne valeur. Une lecture à 14h00m02s aura la nouvelle valeur. Le système est éventuellement cohérent.

Beaucoup d'applications n'exigent pas la cohérence forte, et le critère n'est pas une proportion mais une question simple : que se passe-t-il si un utilisateur lit une valeur vieille de quelques secondes ? Si la réponse est « rien de grave », la cohérence éventuelle convient.

  • Un panier d'achat e-commerce qui met 500 ms à se synchroniser : invisible pour l'utilisateur.
  • Un compteur de likes qui ajuste son chiffre 1 seconde après le clic : acceptable.
  • Une recommandation de produit basée sur l'historique d'achat 5 minutes plus tard : excellent.
  • Un dashboard analytique avec données J-1 : standard.

Pour ces cas, l'eventual consistency permet une disponibilité plus élevée et une scalabilité bien meilleure. C'est la raison pour laquelle DynamoDB, Cosmos DB, Cassandra et la plupart des bases NoSQL retiennent un comportement AP par défaut, tout en offrant une cohérence plus forte en option, à la lecture ou à la configuration.

Quatre catégories de cas exigent absolument la cohérence forte.

Transactions financières. Débit d'un compte et crédit de l'autre doivent être atomiques et immédiatement cohérents. Sinon double dépense possible.

Inventaire critique. Réservation du dernier billet d'avion : si deux clients voient « 1 disponible » simultanément, on ne peut pas vendre les deux.

Sécurité et autorisations. Révocation d'un accès : la cohérence éventuelle « 5 minutes » signifie 5 minutes pendant lesquelles l'utilisateur révoqué garde l'accès.

Verrouillage distribué. Un seul leader élu, un seul worker qui traite un job, pas de cohérence éventuelle possible.

Pour ces cas, utilisez Spanner, Aurora, PostgreSQL, ou DynamoDB avec strong reads (avec son surcoût en latence).

Piège 1, Lecture de sa propre écriture. Un utilisateur écrit, puis lit immédiatement. La lecture peut renvoyer l'ancienne valeur. Solution : read-your-writes consistency (DynamoDB, Cassandra) qui garantit qu'une session voit ses propres écritures.

Piège 2, Cohérence transitive. A écrit X1 puis X2. B lit X1 mais pas X2 puis lit X2 mais pas X1, incohérent dans le temps. Solution : monotonic reads consistency.

Piège 3, Conflit d'écriture concurrent. Deux écritures simultanées sur la même clé sur des nœuds différents. Solution : stratégie de résolution de conflits explicite (timestamp, vecteurs de version, ou « dernière écriture gagne »).

4. Le pattern Saga, transactions distribuées sans 2PC

Section intitulée « 4. Le pattern Saga, transactions distribuées sans 2PC »

Une transaction classique ACID en base de données mono-instance est simple : BEGIN, opérations, COMMIT ou ROLLBACK atomiquement. Sur un système distribué entre plusieurs services, cette atomicité n'existe plus naturellement.

Exemple : valider une commande e-commerce nécessite :

  1. Débiter le compte du client (service Paiement).
  2. Réserver le stock (service Inventaire).
  3. Programmer la livraison (service Shipping).

Si l'étape 3 échoue, il faut annuler les étapes 1 et 2, mais elles sont dans des bases différentes, sur des services différents, peut-être chez des fournisseurs cloud différents.

Two-Phase Commit (2PC), la solution classique qu'on évite plutôt qu'on abandonne

Section intitulée « Two-Phase Commit (2PC), la solution classique qu'on évite plutôt qu'on abandonne »

Le 2PC est un protocole de transaction distribuée qui coordonne plusieurs participants via un coordinateur. Il garantit l'atomicité au prix de :

  • Couplage temporel fort : tous les participants doivent être disponibles simultanément.
  • Blocage : si le coordinateur tombe au mauvais moment, les participants restent verrouillés.
  • Performance médiocre : aller-retour multiples avant de pouvoir committer.

Le 2PC n'est pas mort, il est déplacé. Il reste implémenté et utilisé, dans les moteurs relationnels via XA, dans certains courtiers de messages, et à l'intérieur même des bases distribuées qui s'en servent pour leurs commits internes. Ce qui a changé, c'est le périmètre : on évite désormais une transaction distribuée synchrone entre services lorsqu'on peut accepter des compensations à la place.

La formulation juste est donc la suivante : quand vos participants appartiennent à des équipes, des bases ou des fournisseurs différents, le couplage temporel du 2PC coûte plus cher que la complexité des compensations. La plupart des bases NoSQL ne le proposent d'ailleurs pas, ce qui tranche la question à votre place.

Le pattern Saga remplace le 2PC par une séquence de transactions locales, chacune avec une transaction de compensation qui peut l'annuler.

Saga « Choreographied » : chaque service écoute des événements et publie ses propres événements. Pas de coordinateur central.

1. Order Service → emits "OrderCreated"
2. Payment Service → consumes, debits, emits "PaymentDone"
3. Inventory Service → consumes, reserves, emits "StockReserved"
4. Shipping Service → consumes, schedules, emits "Shipped"
Si étape 3 échoue :
3'. Inventory Service → emits "StockReservationFailed"
2'. Payment Service → consumes, refunds, emits "PaymentRefunded"
1'. Order Service → consumes, marks order as cancelled

Saga « Orchestrated » : un orchestrateur central (ex. AWS Step Functions, Azure Durable Functions) coordonne les étapes et gère les compensations. Plus simple à raisonner, mais réintroduit un point de coordination.

Aspect2PCSaga choreographiedSaga orchestrated
AtomicitéForteCompensationCompensation
CouplageFortFaibleMoyen
PerformanceMédiocreBonneBonne
Complexité de débogageFaibleÉlevéeMoyenne
CohérenceImmédiateÉventuelleÉventuelle

Recommandation pratique : Saga orchestrated avec un service comme Step Functions ou Durable Functions pour les workflows à plus de 4 étapes, la lisibilité du code orchestré l'emporte largement sur la complexité d'un orchestrateur central.

Le choix entre synchrone et asynchrone, et entre cohérence forte et eventual consistency, dépend du domaine métier et des contraintes utilisateurs. Aucun des deux modèles n'est meilleur dans l'absolu, chacun convient à un type d'usage.

Quand la cohérence forte est nécessaire. Certains domaines métier exigent qu'une lecture juste après une écriture renvoie toujours la valeur la plus récente : finance (solde de compte, transferts), inventaire critique (stock à zéro qui doit bloquer la commande), sécurité (révocation immédiate d'un droit d'accès), locks distribués. Sur ces cas, accepter une fenêtre d'incohérence créerait des risques inacceptables. La cohérence forte est alors le bon défaut, malgré son coût en performance et en disponibilité.

Quand l'eventual consistency suffit. Une grande partie des fonctionnalités utilisateur tolère parfaitement une incohérence de quelques centaines de millisecondes : panier d'achat, likes, recommandations, tableaux de bord agrégés, fil d'activité. Dans ces cas, accepter l'eventual consistency simplifie l'architecture, améliore la disponibilité, et n'est pas perceptible par l'utilisateur. La règle pratique consiste à choisir l'eventual consistency par défaut pour ce type de fonctionnalité, et à renforcer ponctuellement aux endroits où le métier l'exige.

Le pattern Saga implique un changement culturel. Adopter le Saga (suite de transactions locales + compensations) demande à l'équipe d'accepter que certaines incohérences temporaires soient visibles. Une commande peut être créée, payée, puis annulée 30 secondes plus tard parce que le stock manquait, et l'utilisateur reçoit alors deux notifications successives. Ce comportement est le prix de la résilience sur architecture distribuée. Les équipes habituées à un modèle transactionnel ACID monolithique doivent ajuster leur conception UX pour rendre ces compensations compréhensibles.

Synchrone ou asynchrone : le critère décisif. Le synchrone reste pertinent quand la latence importe (un appel utilisateur attend le résultat) et quand la simplicité de raisonnement prime (peu d'étapes, peu d'acteurs). L'asynchrone devient pertinent dès que la chaîne d'événements implique plusieurs services, qu'il faut absorber des pics, ou que l'on veut découpler les disponibilités respectives. Sur les architectures à beaucoup de microservices, l'asynchrone par défaut limite la propagation des pannes, sur un monolithe ou une petite application, le synchrone direct reste souvent plus simple à raisonner.

  • Synchrone = j'attends la réponse (REST, gRPC). Asynchrone = je publie un message, je continue (queue, event bus).
  • CAP theorem : la tolérance aux partitions ne se choisit pas. L'arbitrage entre cohérence et disponibilité ne se pose que pendant une partition ; hors partition, PACELC déplace le compromis vers la latence.
  • Une base mono-instance n'a pas de position CAP : elle n'est pas partitionnable, elle est simplement indisponible quand elle tombe.
  • Eventual consistency est le comportement par défaut de la plupart des bases distribuées, adapté quand une lecture obsolète de quelques secondes est sans conséquence (panier, likes, recommandations, tableaux de bord).
  • Cohérence forte reste obligatoire pour : finance, inventaire critique, sécurité, locks distribués.
  • Pattern Saga remplace le 2PC entre services : transactions locales et compensations, en chorégraphie ou en orchestration. Le 2PC lui-même reste employé à l'intérieur d'un moteur ou via XA.
  • Le choix synchrone/asynchrone dépend du nombre de services impliqués, de la sensibilité à la latence et de la tolérance aux pannes propagées, il n'y a pas de défaut universel.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn