Oyun Kitabı
Modèle de boîte d'envoi/boîte de réception dans les systèmes de paiement (Modele DE Boite Denvoiboite DE Reception Dans Les Systemes DE Paiement)
Si l'écriture dans la base de données et la publication d'un événement ne font pas partie de la même transaction, l'une d'elles sera perdue ou répétée. Diffusions de la boîte d'envoi, déduplication de la boîte de réception du consommateur.
Moteur de paiement distribué
Partie 7 de 22
Une série d'architectures de paiement distribuées qui comblent le fossé entre la capture et l'achèvement.
Deux écritures, pas une transaction
Lorsqu'un service décide de « commande passée », il souhaite généralement faire deux choses : écrire une ligne dans la base de données et publier un événement dans une file d'attente/un courtier de messages. Since these two writes go to different systems, they cannot be done atomically in a single transaction. The space between them is called "dual-write hole".```text DbContext.SaveChanges() → veritabanına yazıldı Broker.Publish(event) → burası başarısız olursa event kaybolur (veya sıra tersine çevrilirse, event gönderilir ama DB commit rollback olur)
## Concepts à la première mention```text
📦 Dual-Write Problemi
Aynı iş kararının iki farklı sisteme (DB ve broker) atomik olmayan iki yazma ile yansıtılmaya çalışılması.
📦 Outbox
İş kararıyla aynı veritabanı transaction'ında yazılan, sonradan ayrı bir süreç tarafından yayınlanan olay tablosu.
📦 Lease
Bir publisher sürecinin, outbox'taki bir satırı işlerken diğer publisher süreçlerinin aynı satırı almasını önleyen geçici kilit.
📦 Inbox
Tüketici tarafında, gelen bir olayın işlenmeden önce kaydedildiği ve tekrarları filtreleyen tablo.
📦 Effectively-once
At-least-once teslimat ile idempotent tüketicinin birleşiminden elde edilen, pratikte “tam olarak bir kez” gibi davranan sonuç.
```La boîte d'envoi résout le problème du côté expéditeur (atomicité d'écriture + diffusion). Inbox résout le problème du destinataire (relivraison). Ensemble, ils établissent un flux d’événements fiable de bout en bout.
## Comment ouvrir le trou à double écriture
Si un gestionnaire envoie un événement au courtier immédiatement après avoir écrit dans la base de données, le système peut planter entre deux étapes distinctes. Si l'écriture de la base de données réussit mais que l'appel du courtier échoue, la décision commerciale persiste mais l'événement n'est jamais publié — les services en aval ne seront jamais informés de cette décision.```text
1. DB: Order.Status = Captured ✓ (commit edildi)
2. Broker.Publish(OrderCaptured) ✗ (network hatası, process crash)
Sonuç: Order tablosunda Captured var, ama hiçbir servise event gitmedi
```L'inverse est également possible : l'événement est publié mais la transaction DB est annulée ; Dans ce cas, les services en aval réagissent à un événement qui ne s'est jamais produit.
## Boîte d'envoi : déplacez l'écriture et la diffusion vers la même transaction
Le modèle de boîte d'envoi écrit l'événement dans une table de boîte d'envoi au sein de la même transaction de base de données que la décision commerciale, plutôt que de le diffuser directement au courtier. Cette ligne est désormais atomiquement conservée par les décisions commerciales : soit les deux s'engagent, soit aucun des deux.```text
Tek transaction:
UPDATE orders SET status = 'Captured' WHERE id = 42;
INSERT INTO outbox (event_type, payload, dispatched_at) VALUES ('OrderCaptured', ..., NULL);
COMMIT
```Un processus d'éditeur distinct analyse périodiquement les lignes `dispatched_at IS NULL` dans la boîte d'envoi, les publie sur le courtier et, en cas de succès, remplit le champ `dispatched_at`. Si cet éditeur travaille avec plusieurs instances, un mécanisme de bail (verrouillage à court terme) est utilisé pour empêcher deux instances de recevoir la même ligne en même temps.```text
Publisher A: satır #7'yi lease'ler (30 sn) → broker'a yayınlar → dispatched_at = now()
Publisher B: satır #7 lease'li, atlar; başka satır arar
```Cette étape garantit que l'événement est diffusé au moins une fois, mais il peut être diffusé deux fois si l'éditeur plante. C'est pourquoi il est nécessaire de se défendre du côté des consommateurs.
## Boîte de réception : déduplication côté consommateur
Puisque Outbox garantit au moins une diffusion, le consommateur peut recevoir le même événement plusieurs fois. Au lieu de traiter l'événement directement, le modèle de boîte de réception l'écrit d'abord dans la table de la boîte de réception avec un identifiant d'événement unique ; Si cette écriture existe déjà (violation de contrainte d'unique), l'événement n'est pas à nouveau traité.```text
Tüketici event alır: event_id=evt_001
INSERT INTO inbox (event_id, status) VALUES ('evt_001', 'received')
→ başarılı: iş bir job'a kuyruklanır
→ unique constraint hatası: zaten görülmüş, sessizce atlanır
```## Boîte d'envoi + Boîte de réception = effectivement une fois
La boîte d'envoi garantit que la diffusion n'est pas perdue (au moins une fois). Inbox garantit qu'une même diffusion n'est pas traitée deux fois du côté du consommateur (consommateur idempotent). Lorsque ces deux éléments se combinent, le système se comporte pratiquement « exactement une fois » — c’est ce qu’on appelle effectivement une fois ; Les garanties vraies exactement une fois sont presque impossibles dans les systèmes distribués, mais cette combinaison en est une approximation adéquate dans la pratique.```text
Outbox (gönderen) → at-least-once yayın
Inbox (alan) → idempotent tüketim
─────────────────────────────────────────
Toplam davranış → effectively-once
Les confrontations les plus déroutantes de cet épisode```text
❌ DB'ye yazıp hemen ardından broker'a publish etmek güvenlidir ✓ Bu iki adım atomik değildir; aralarında dual-write hole vardır
❌ Outbox tek başına tekrar teslimatı önler ✓ Outbox at-least-once garanti eder; tekrar teslimata karşı tüketici tarafında inbox gerekir
❌ Lease, kalıcı bir kilittir ✓ Lease geçici ve süreli bir kilittir; publisher crash olursa süre dolunca serbest kalır
❌ Effectively-once, exactly-once ile aynı şeydir ✓ Exactly-once dağıtık sistemlerde pratik değildir; effectively-once, at-least-once + idempotency'nin sonucudur
## Liste de contrôle de la configuration de votre boîte d'envoi/boîte de réception
1. La rédaction de votre décision commerciale dans la base de données et la publication de l'événement se font-elles dans la même transaction ou en deux étapes distinctes ?
2. Si votre éditeur Outbox fonctionne avec plusieurs instances, disposez-vous d'un mécanisme de location qui empêche deux instances de recevoir la même ligne ?
3. Si Publisher plante, la ligne peut-elle être réessayée après l'expiration du bail, ou restera-t-elle « louée » pour toujours ?
4. Du côté du consommateur, existe-t-il une contrainte unique pour l'identifiant d'événement dans la table de votre boîte de réception ?
5. Existe-t-il une métrique/alarme qui suit le nombre de lignes avec `dispatched_at IS NULL` dans la boîte d'envoi (indicateur de retard de publication) ?
Si vous ne pouvez pas répondre avec confiance à deux de ces cinq questions, votre système est probablement encore vulnérable à un trou de double écriture.
## Choses à retenir de cette section
1. L'écriture dans la base de données et la publication d'un événement vont vers des systèmes différents et ne sont pas atomiques ; Cet espace est un trou à double écriture.
2. La boîte d'envoi garantit l'atomicité pour l'expéditeur en écrivant l'événement dans la même transaction que la décision commerciale ; Un processus d'éditeur distinct le publie.
3. Le bail empêche plusieurs instances d'éditeur de traiter la même ligne de boîte d'envoi en même temps ; Il s'agit d'un verrouillage temporaire et non permanent.
4. Inbox empêche le même événement d'être traité deux fois du côté du consommateur ; Rend la garantie au moins une fois d'Outbox idempotente.
> Un événement publié sans Outbox peut disparaître dès qu'il est lancé. Un événement reçu sans Inbox peut être traité deux fois, ce qui rend la perte deux fois plus coûteuse.
FAQ
Frequently asked questions
Quel est le problème de double écriture ?
Essayer de refléter la même décision commerciale dans deux systèmes différents (base de données et courtier) avec deux écritures non atomiques.
Qu'est-ce que la boîte d'envoi ?
Table d'événements écrite dans la même transaction de base de données que la décision commerciale, publiée ensuite par un processus distinct.
Est-il vrai qu'« il est sûr d'écrire dans la base de données puis de publier immédiatement sur le courtier » ?
Ces deux étapes ne sont pas atomiques ; Il y a un trou de double écriture entre eux
Que corrige cette section ?
Cette section décrit les modèles de boîte d'envoi et de boîte de réception qui comblent cette lacune. L'écriture dans la base de données et la publication d'un événement vont vers des systèmes différents et ne sont pas atomiques ; Cet espace est un trou à double écriture. Lorsqu'un service décide de « commande passée », il souhaite généralement faire deux choses : écrire une ligne dans la base de données et publier un événement dans une file d'attente/un courtier de messages. Étant donné que ces deux écritures sont destinées à des systèmes différents, elles ne peuvent pas être effectuées de manière atomique en une seule transaction. L'espace entre eux est appelé « trou à double écriture ».
Principes d'ingénierie appris
- Si l'écriture de base de données et la publication d'événements ne font pas partie de la même transaction, le trou de double écriture reste ouvert ; La boîte d'envoi comble cette lacune du côté de l'expéditeur.
- Inbox est le complément obligatoire qui rend la garantie au moins une fois d'Outbox idempotente du côté du consommateur.
- En effet, une fois ne remplace pas une fois exactement ; C’est le résultat pratique produit par une livraison au moins une fois et une consommation idempotente.
Continuer la lecture
Continuer la lecture
Suivant en série
Preuve de paiement et statut de paiement : pourquoi il ne faut pas confondre
Les preuves, c'est ce que PSP prétend. L'état est ce que vous décidez. Si vous conservez ces deux éléments dans le même registre, vous saurez à qui faire…
Suivant en série
Fiabilité des webhooks dans les systèmes de paiement
Les webhooks se répètent, disparaissent, arrivent dans le désordre et avec du retard. Vérifiez la signature, donnez un ACK rapide, n'exécutez jamais de…
Même série
Demande d'idempotence (transaction sécurisée répétable) au-delà de l'API (interface de programmation d'application)
L'idempotence n'est pas un simple en-tête. Il s'agit d'une pile de défense qui doit être configurée séparément sur cinq couches différentes, de la clé API…