Two-Phase Commit (2PC)
Comment garantir qu'une transaction soit validée partout ou nulle part lorsqu'elle touche N nœuds indépendants — au prix d'un blocage possible si le coordinateur tombe.
Problème
Une transaction métier doit modifier de façon atomique plusieurs ressources distinctes (par exemple débiter un compte fournisseur et créditer un compte logistique dans deux SGBD différents, ou bien valider simultanément un message AS4 reçu et l'inscription en queue d'un APERAK). Sans coordination, l'une peut commit et l'autre échouer, laissant le système dans un état incohérent. La propriété ACID Atomicity doit être préservée à travers la frontière de chaque ressource.
Forces
- Latence : 2PC ajoute deux round-trips réseau au chemin critique (prepare + commit).
- Blocage : si le coordinateur tombe entre prepare et commit, les participants restent en état préparé (locks tenus) jusqu'au retour du coordinateur ou intervention humaine.
- Détection de panne : 2PC suppose un environnement fail-stop ; les pannes byzantines ne sont pas traitées.
- Couplage temporel fort : tous les participants doivent être disponibles simultanément pendant prepare.
- Standardisation : XA/Open Group (1991) et JTA (J2EE) ont normalisé les API ; mais l'implémentation diverge fortement.
Solution
Le coordinateur orchestre deux phases distinctes. Phase 1 (prepare) : le coordinateur envoie un PREPARE à chaque participant ; chacun fait toutes les vérifications, écrit son journal en redo/undo et répond VOTE-COMMIT (« je peux ») ou VOTE-ABORT (« non »). Phase 2 (commit/abort) : si tous votent COMMIT, le coordinateur écrit COMMIT dans son journal et envoie COMMIT à tous ; sinon il envoie ABORT. Les participants ack et libèrent les locks. La phase 1 préserve la durabilité des journaux participants ; la phase 2 garantit l'atomicité globale.
Structure
┌─────────── Coordinator ───────────┐
│ │
│ Phase 1: PREPARE │
│ ─────────► Participant A │
│ ─────────► Participant B │
│ ─────────► Participant C │
│ │
│ ◄──────── VOTE-COMMIT (A) │
│ ◄──────── VOTE-COMMIT (B) │
│ ◄──────── VOTE-COMMIT (C) │
│ │
│ [WRITE "commit" in log] ★ DURABLE │
│ │
│ Phase 2: COMMIT │
│ ─────────► A, B, C │
│ ◄──────── ACK from all │
└────────────────────────────────────┘
If any VOTE-ABORT:
Coordinator writes "abort", broadcasts ABORT → participants rollback.
If coordinator crashes after ★:
All participants stay BLOCKED (locks held)
until coordinator recovery reads log and resends COMMIT/ABORT. Implémentation EDI
En 2026, 2PC n'a quasiment plus sa place dans un hub EDI moderne — il est inadapté à des flux multi-partenaires asynchrones où chaque partie a son propre tempo. Reste un cas résiduel : la mise à jour atomique entre une base de messages (PostgreSQL) et une queue persistante (RabbitMQ avec extension XA, IBM MQ) au sein d'un même hub. Concrètement, le pattern Outbox a presque toujours supplanté ce besoin. Quand un hub doit interagir avec un ERP transactionnel (SAP NetWeaver via JCA) qui supporte XA, 2PC reste une option pour garantir que le message EDIFACT ingéré et l'inscription dans la table SAP commit ensemble. La règle pratique : si le partenaire est externe (AS2, AS4, OFTP2), ne jamais inscrire le partenaire dans une transaction XA — utiliser une saga.
Anti-patterns
- Étendre 2PC à un partenaire externe via Internet — la moindre latence ou panne réseau bloque la transaction durablement.
- Coordinateur unique sans HA — son crash arrête tous les flux jusqu'à recovery manuel.
- Mélanger ressources XA et non-XA dans la même transaction — la garantie ACID n'est plus que partielle (et c'est pire que rien).
- Confondre 2PC et Saga — 2PC verrouille, Saga compense ; ce ne sont pas des alternatives au même problème.
- Présenter 2PC comme « transparent pour le développeur » — l'analyse des deadlocks XA reste l'un des sujets les plus complexes de l'ingénierie back-end.
Patterns liés
- Three-Phase Commit (3PC) — variante non-bloquante au prix d'une round-trip supplémentaire et d'hypothèses synchrones plus fortes.
- Saga (orchestration) — alternative recommandée pour les flux EDI longs où le blocage n'est pas acceptable.
- Transactional Outbox — supplante 2PC dans le cas DB+queue local en publiant les événements depuis la même transaction locale.
- Consensus (Raft) — variante moderne du consensus distribué adoptée par etcd, CockroachDB.
Sources
- Gray J. — Notes on Database Operating Systems, IBM Research RJ2188, 1978. Le papier fondateur où 2PC est décrit pour la première fois. jimgray.azurewebsites.net
- X/Open Distributed Transaction Processing — The XA Specification, X/Open CAE Specification, 1991. La normalisation de 2PC qui a structuré JTA, MS DTC, Tuxedo.
- Bernstein P., Hadzilacos V., Goodman N. — Concurrency Control and Recovery in Database Systems, Addison-Wesley, 1987, chap. 7.
- Kleppmann M. — Designing Data-Intensive Applications, O'Reilly 2017, chap. 9 (« Distributed transactions and 2PC »).
- Pat Helland — Life Beyond Distributed Transactions: An Apostate's Opinion, ACM Queue 2007, qui explique pourquoi 2PC ne tient pas à grande échelle.