Comment construire fail-safe traitement de millions de transactions par jour
Texte intégral de l'article
1) Ce que signifie fail-safe pour les transactions
Fail-safe est quand toute situation de défaillance conduit soit à un arrêt sécurisé, soit à un état compensable sans perte d'argent et de données. Objectifs :- « Doubles débits/crédits » = 0.
- Transactions/événements perdus = 0.
- SLO prédictible par latence/livraison, modes de dégradation clairs et DR.
La base est les invariants monétaires (la vérité de l'équilibre en un seul endroit), l'idempotence, la livraison convenue des événements.
2) Principes architecturaux (en bref)
1. Source unique de la vérité : bilan et comptabilité - dans Ledger/Wallet. Les services autour gardent les états des processus, pas l'argent.
2. Idempotency everywhere : toutes les opérations d'enregistrement prennent 'Idempotency-Key' ; la répétition renvoie le même résultat.
3. Evénement avec garantie de livraison : outbox/CDC, file d'attente, DLQ, dedup.
4. Sagas et compensations, pas « modifications manuelles ».
5. Back-pression et priorités : le système ralentit mais ne s'effondre pas.
6. Observabilité par défaut : logs structurés, tracing, métriques.
7. Multi-région et DR : actif-actif/actif-passif, exercice régulier.
3) Topologie de référence
Edge/API GW ──Command API ──App Service (Sagas)
│           │
│         (Outbox TX)
RateLimit     Outbox Table ──Publisher ──Kafka/Pulsar ──Consumers
│                      │
WAF                     └─DLQ/Replay
│
└─Ledger/Wallet (ACID, idempotent debit/credit)
│
└─CDC/Changefeed ──DWH/BI/ReconLieux clés : Outbox (enregistrement atomique de l'équipe et « brouillon » de l'événement), Publisher (exactement une livraison), Consumers (idempotent, avec clé de déduplication), DLQ/Replay (répétitions contrôlées).
4) Invariants monétaires et cohérence
La vérité sur le bilan est Ledger (ACID, transactions sérialisées ou ordre strict sur le compte).
Les commandes monétaires : 'debit', 'credit', 'hold', 'commit', 'rollback' sont idempotentes.
Les processus combinés sont construits comme des sagas :- 'Autorize → settle → credit '(dépôt/dépôt),' request → submit → settled/failed '(paiement/retrait),' refund/void '(compensation).
- Pas d'édition directe des bilans en contournant Ledger.
5) Idempotence : conception de clés
La clé doit identifier de manière unique l'activité :- `bet_id+amount+currency`, `payment_intent+capture_id`, `payout_id`, `chain_txid`.
- Stocker le résultat par clé (response cache). Une répétition avec la même clé → le même body/status.
- Contrôler la non-conformité : même clé avec une somme différente → 'IDEMPOTENCY _ MISMATCH'.
6) Files d'attente, ordre et dedup
Les effets exactly-once ne sont pas obtenus par le transport, mais par les consumers idempotent + stockage de déduplication (LRU/Redis/DB c TTL).
Gardez l'ordre par clé (partition key = 'account _ id/round _ id/player _ id').
Pour les clés « hétérogènes », l'état et les commutateurs (state machine per entity).
DLQ est obligatoire : après N tentatives - dans un sujet isolé avec une cause humaine.
7) Outbox/CDC : pourquoi les événements « ne sont pas perdus »
Dans le cadre d'une transaction dans la base de données du service, nous enregistrons à la fois le changement d'entreprise et l'enregistrement dans l'outbox.
Un éditeur distinct lit l'outbox et publie sur le bus de confirmation.
Alternativement, CDC (Change Data Capture) au niveau de la base de données (Debezium/logue de réplication).
Pas de « logs d'événements » au-delà de la transaction est une source de perte.
8) Back-pression et priorités
Jetons et quotas à l'entrée (per tenant/brand/region).
Files d'attente prioritaires : les chemins monétaires sont supérieurs à la promo/télémétrie.
En cas de surcharge : modes 'no new sessions/requests', gel des fiches secondaires, conservation du noyau.
Auto-dégradation : réduire la fréquence des tâches de fond, étendre dynamiquement les workers critiques.
9) Durabilité multirégionale
Un atout pour l'API et les files d'attente, un Ledger local (ou global avec un sharding par région/devise).
Résidence de données : argent/PII/journaux ne sont pas croisés sans règles explicites.
La réplication interrégionale des événements est asynchrone, marquée « region ».
RPO/RTO : baiser RPO ≤ 5 minutes, RTO ≤ 30 minutes ; vérifiez régulièrement.
10) SLO/SLI et dashboards
Repères (exemple) :- p95 'autorize/debit/credit' <150-300 ms (chemin interne).
- p95 end-to-end « komanda→sobytiye dans le bus » <1-2 s.
- Livraison de webhooks/événements externes p99 <5 min
- « Transactions perdues/dupliquées » = 0 (vérifications contractuelles).
Métriques : latency p50/p95/p99, error rate (4xx/5xx/business), consumer/queue lag, retry storms, settle lag, webhook lag, taille DLQ, fréquence 'IDEMPOTENCY _ MISMATCH'.
11) Observation et audit
Logs JSON structurés avec 'trace _ id', 'idempotency _ key', ID d'entreprise, codes d'erreur.
OpenTelemetry : Tracing HTTP/gRPC/DB/pneus, Spans saga.
Audit WORM : journaux de changement critique immuables (limites, clés, configi promo/jackpots).
Masque PII/secrets, baquets régionaux, RBAC/ABAC pour l'accès aux logs.
12) Test de fiabilité
Tests contractuels : répétitions/doublons, out-of-order, idempotence, dedup.
Charge : profil des pics (x10), stabilité des files d'attente et OBD.
Cas de chaos : chute de Ledger/porte-monnaie, chute des files d'attente/régions, retards du CDC, « tempête » des retraits.
Game Days : Exercice régulier de DR et incidents, avec mesure MTTR.
13) Entrepôts et données
OLTP pour l'argent : OBD transactionnelle (RPO≈0), indices stricts, niveaux sérialisables par entité critique.
Cache (Redis) - seulement pour accélérer, pas pour la « vérité ». TTL + jitter, protection contre le cache stampede.
OLAP/DWH - pour les rapports/analyses. Flux de CDC/bus, sans charge sur OLTP.
Les circuits de données sont versionnés ; migration sans downtime (expand/contract).
14) Orchestration de retraits
Backoff + jitter exponentiel, dedline/timeout sur RPC.
Une répétition idempotente sur chaque couche (client → service → consommateur).
Quotas de retraite, pour se protéger contre les « tempêtes » (circuit breaker, requests hedged, le cas échéant).
Replay du DLQ uniquement dans les fenêtres « sûres », avec limitation de vitesse.
15) Sécurité des transports
Les mTLS sont partout S2S, les jetons à courte durée de vie (OAuth2 CC), les signatures de corps (HMAC/EdDSA) pour les webhooks.
Secrets dans Vault/HSM, rotation, clés par marque/région.
Les politiciens du privilège, les « quatre yeux » sur les opérations manuelles.
16) Contrats exemplaires (fragments)
L'équipe de débit idempotent
POST /v1/wallet/debit
Headers: X-Idempotency-Key: debit_pi_001, X-Trace-Id: tr_a1b2
{
"account_id":"acc_42",  "amount":{"minor_units":5000,"currency":"EUR"},  "reason":"payout",  "reference_id":"po_001"
}
→ 200 { "status":"committed", "entry_id":"e_77" }
(répétition → même réponse)Événement de outbox
json
{
"event_id":"uuid",  "event_type":"wallet. debit. committed",  "occurred_at":"2025-10-23T16:21:05Z",  "account_id":"acc_42",  "amount_minor":5000,  "currency":"EUR",  "reference_id":"po_001",  "idempotency_key":"debit_pi_001",  "schema_version":"1. 3. 0"
}17) Chèques-feuilles
Plate-forme/opérateur
- La vérité sur l'équilibre est un Ledger ; Il n'y a pas de solution de rechange.
- Toutes les opérations d'écriture avec 'Idempotency-Key' ; la réponse est stockée par clé.
- Outbox/CDC sur tous les enregistrements de domaine, DLQ et replay géré.
- Files d'attente avec priorités, back-pressure, modes de dégradation.
- Les clés de partition sont choisies par clé d'entreprise ; les consommateurs sont idempotentes.
- SLO-dashboards, OpenTelemetry, audit WORM.
- Exercices réguliers de RD/xaoc, essais contractuels/de charge.
- Data residency, cryptage, Vault/HSM, rotation des clés.
Fournisseurs/intégrations
- J'envoie 'Trace-Id'/' Idempotency-Key', prêt à être livré à nouveau.
- Les webhooks sont signés et dédupliqués.
- Les versions des régimes/contrats sont respectées (semver, deprecation).
18) Drapeaux rouges (anti-modèles)
L'équilibre change selon le webhook sans commande dans Ledger.
Manque d'idempotence → doubles prélèvements/crédits.
Publier des événements en contournant outbox/CDC.
Monolithe sans back-pression : Le pic de trafic fait tout.
Mélange d'OLTP et de rapports : BI frappe une OBD de combat.
Absence de DLQ/repli ; ingestion « silencieuse » des erreurs.
Il n'y a pas d'isolement régional PII/argent ; clés communes à plusieurs marques.
Édition manuelle des balances/statuts dans la base de données.
19) Résultat
Le fail-safe de millions de transactions par jour est sur les invariants et la discipline : une source unique de vérité, des commandes idempotentes, des sagas et des outbox/CDC, l'ordre et le dédoublement dans les files d'attente, l'observation et les dégradations gérables. Ajoutez des mandats d'accès, des pratiques de RD et des exercices réguliers - et obtenez un système où l'argent se déplace rapidement et une seule fois, les événements ne sont pas perdus, et l'augmentation du trafic et les perturbations deviennent des risques gérables plutôt que des surprises.
