如何建立故障安全處理每天數百萬筆交易
文章全文
1)失敗安全對交易意味著什麼
失靈安全是指任何失靈情況都會導致安全停止或可補償狀態而不會丟失金錢和數據。目標是:- 「雙重借記/積分」=0。
- 丟失的事務/事件=0。
- 可預測的潛伏期/遞送SLO,清晰的降解模式和DR。
基礎是貨幣不變性(一個位置的資產負債表真理),相等性,協調的事件傳遞。
2)建築原理(簡稱)
1.單一真相來源:資產負債表和會計-在Ledger/Wallet。周圍的服務保持流程狀態而不是金錢。
2.Idempotency everywhere:所有「記錄」操作都接受「Idempotency-Key」;重復返回相同的結果。
3.交付保證事件:outbox/CDC、隊列、DLQ、dedup。
4.傳奇和補償,而不是「手動編輯」。
5.後壓和優先級:系統放慢但不會崩潰。
6.默認可觀察性:結構化日誌、跟蹤、度量。
7.多區域和DR:資產/資產放電,定期演習。
3)參考拓撲
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/Recon關鍵位置:Outbox(團隊的原子記錄和事件的「草稿」),Publisher(正好是一次交付),Consumers(具有去除鍵),DLQ/Replay(受控重播)。
4)現金不變性和一致性
資產負債表的真相是Ledger(ACID,可序列化的事務或嚴格的計數排序)。
現金團隊:「debit」,「credit」,「hold」,「commit」,「rollback」是偶然的。
組合過程構造為傳奇:- 「authorize → settle → credit」(存款/設置),「request → submit → settled/failed」(付款/輸出),「refund/void」(補償)。
- 沒有直接編輯資產負債表繞過Ledger。
5)相似性: 密鑰設計
密鑰必須唯一標識業務操作:- `bet_id+amount+currency`, `payment_intent+capture_id`, `payout_id`, `chain_txid`.
- 按鍵存儲結果(響應緩存)。具有相同鍵的重播→相同的車身/狀態。
- 控制不匹配:具有不同金額的相同密鑰→ 「IDEMPOTENCY_MISMATCH」。
6)隊列,順序和背叛
Exactly once的效果不是通過運輸來實現的,而是通過使用者+去勢存儲(LRU/Redis/DB c TTL)來實現的。
按鍵保持順序(partition key='account_id/round_id/player_id")。
對於「異構」密鑰,狀態轉換和交換機(state machine per entity)。
DLQ是強制性的:經過N的嘗試-進入一個具有人為原因的孤立主題。
7) Outbox/CDC: 為什麼事件「不會丟失」
作為一項交易的一部分,我們記錄服務的DB 中的業務變更和outbox中的記錄。
一個單獨的出版商讀取outbox並發布到確認總線。
或者-DB級別的CDC(更改數據捕獲)(Debezium/復制日誌)。
交易之前沒有「事件日誌」是損失的來源。
8)背靠背壓力和優先事項
令牌罐和入口配額(per tenant/brand/region)。
優先排隊:現金路徑高於促銷/遙測。
過載時:「no new sessions/requests」模式,凍結次要幻影,保存核心。
自動降解:減少背景任務的頻率,動態擴展關鍵操作者。
9)多區域可持續性
API和隊列的資產資產,本地Ledger(或具有區域/貨幣沖壓的全局資產)。
數據駐留:沒有明確的規則,金錢/PII/日誌不會交叉。
區域間事件復制是異步的,帶有「區域」標記。
RPO/RTO:瞄準RPO ≤ 5分鐘,RTO ≤ 30分鐘;定期檢查。
10)SLO/SLI和dashbords
地標(示例):- p95 'authorize/debit/credit' <150-300 ms(內部路徑)。
- p95端到端「總線中的komanda→sobytiye 」<1-2 s。
- 網絡圖書/外部事件交付p99 <5分鐘。
- 「丟失/重復事務」=0(合同檢查)。
指標:latency p50/p95/p99, error-rate (4xx/5xx/business), consumer/queue lag, retry storms, settle lag, webhook lag, DLQ大小,'IDEMPOTENCY_MISMATCH'頻率。
11)可觀察性和審計
帶有「trace_id」,「idempotency_key」,Business ID和錯誤代碼的結構化JSON邏輯。
OpenTelemetry: HTTP/gRPC/DB/總線預告片, SAG.
WORM審核:不變的關鍵更改日誌(限制、密鑰、促銷標誌/大獎)。
掩蓋PII/秘密,區域垃圾箱,RBAC/ABAC訪問日誌。
12)可靠性測試
合同測試:重播/復制,訂單退出,平均水平,滯後。
負載:峰值輪廓(x 10),隊列穩定性和DB。
混沌案例:Ledger/錢包掉落,排隊/地區,CDC延遲,「風暴」撤退。
Game Days: MTTR測量的常規DR演習和事件。
13)存儲和數據
金錢下的OLTP:交易DB(RPO≈0),嚴格的索引,按關鍵實體序列化的級別。
緩存(Redis)-僅用於加速,而不適用於「真相」。TTL+jitter, cache stampede防護。
OLAP/DWH-用於報告/分析。從CDC/總線流出,OLTP上沒有負載。
數據方案被驗證;無市區遷移(expand/contract)。
14)復古樂團
指數backoff+jitter,RPC上的截止日期/時間。
每個層(客戶→服務→消費者)上的等效重復。
Retrai配額,保護自己免受「風暴」(適當的巡回決勝局,合格的要求)。
從DLQ返回到僅限速度的「安全」窗口。
15)運輸安全
mTLS到處S2S,短壽命令牌(OAuth2 CC),車身簽名(HMAC/EdDSA)用於webhook。
Vault/HSM中的秘密,輪換,按品牌/區域鍵。
政治家least privilege,「四眼」手動操作。
16)示例合同(碎片)
排位賽球隊借記
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" }
(重復→相同答復)來自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)支票單
平臺/操作員
- 資產負債表的真相是一位Ledger;沒有解決辦法。
- 所有帶有「Idempotency-Key」的寫作操作;按鍵存儲響應。
- Outbox/CDC對所有域條目、DLQ和托管重置。
- 具有優先級、後壓、降級模式的隊列。
- Partition-keys是按業務密鑰選擇的;消費者是同等的。
- SLO-dashbords, OpenTelemetry, WORM審核。
- 定期DR/xaoc演習,合同/負載測試。
- 數據駐留、加密、Vault/HSM、密鑰旋轉。
提供商/集成商
- 發送「Trace-Id」/「Idempotency-Key」,準備重新交付。
- Webhooks已簽名並被重復數據消除。
- 電路/合同版本必須遵守(semver, deprecation)。
18)紅旗(反模式)
在Ledger中沒有團隊的情況下,平衡隨網絡而變化。
缺乏相同能力→雙重註銷/貸款。
發布繞過outbox/CDC的事件。
沒有後壓的巨石:交通高峰壓倒一切。
OLTP和報告的混合:BI擊中了戰鬥DB。
缺少DLQ/反射;「安靜」攝入錯誤。
沒有PII/貨幣的區域隔離;共享多個品牌的密鑰。
手動編輯DB中的平衡/狀態。
19)結果
Fail-safe每天處理數百萬個事務是關於不變性和紀律:單一的真相來源,相反的命令,傳奇和outbox/CDC,隊列中的順序和祖先,可觀察性和可管理的退化。添加訪問任務、DR實踐和定期演習-並獲得一個系統,其中資金快速移動,只有一次,事件不會丟失,流量增加和中斷成為風險驅動而不是驚喜。
