傳奇和分布式交易
傳奇是一種長期的業務交易,在不同的服務/存儲中分為一系列本地步驟。每個步驟都具有補償作用,可在部分失敗時回滾步驟效果。與2PC/3PC不同,傳奇不會阻止全球鎖定,並且適用於允許事件一致性的微服務,多區域和高負載。
1)何時選擇傳奇(何時不選擇)
適合:- 冗長/多階段業務流程(訂單→付款→準備→交付)。
- 沒有共享事務的不同域和存儲。
- 需要高可用性和水平擴展。
- 固體ACID原子性是關鍵的(例如,在單個註冊表內轉移大量)。
- 沒有明確的可賠償性(不可能「保留」或取消效果)。
- 法律/監管限制要求嚴格隔離和「即時」不變性。
2) Sag模型
1.編排(Saga Orchestrator):中央協調員管理步驟和補償。
優點:顯式流量、誤差控制、簡化的遙測。
缺點:集中點,「胖」協調員的風險。
2.編舞(Choreography):沒有中心-步驟是由事件引發的(「服務A使X →服務B反應」)。
優點:連接性弱,縮放簡單。
缺點:更難跟蹤/借記流,規則「蔓延」的風險。
3.TCC (Try-Confirm/Cancel):每個步驟都是「冗余」(Try),然後是確認(Confirm)或取消(Cancel)。
優點:更接近偽雙相協議,管理資源。
缺點:實現接口的成本更高;要求「Try」持有人的時間。
3)步進和補償設計
不變式:明確表述步驟「之前/之後」的真實內容(例如「殘余≥ 0」)。
補償≠反向交易:這是取消業務效果的邏輯操作(返還,釋放,恢復)。
相等性:步驟和補償器都必須安全重復(通過「operation_id」)。
Taymauts:每個步驟都有截止日期;遲交會引發賠償。
不退款效果:將它們單獨固定(通知、電子郵件)並允許「best effort」。
4)一致性和順序
Eventual consistency:用戶可以看到時間差異;UX-具有「等待「/旋轉器/狀態。
按鍵順序:交換步驟按業務鍵(order_id)分組以排序事件。
重復數據消除:使用TTL存儲處理日誌('operation_id' →狀態)。
5)運輸和可靠性
Outbox模式:將事件寫入同一事務內的本地「outbox」表格,然後異步發布到總線。
收件箱/Idempotency store:消費者方面-已經處理的消息日誌。
Exactly once有效:「outbox+idempotent consumer」給出了實際的「恰好一次」。
DLQ:用於具有豐富元信息和安全紅土的「有毒」消息。
6)錯誤策略,retrai,backoff
我們只重復偶數步驟;記錄操作-使用「Idempotency-Key」。
指數backoff+jitter;限制嘗試和傳奇的總截止日期。
當系統降解時-電路斷路器和分解分解(例如,取消傳奇的次要分解)。
業務沖突(「409」)-同意或補償並完成後的重復。
7)管弦樂隊: 職責和結構
功能:- 傳奇狀態跟蹤:「PENDING → RUNNING → COMPENSATING → DONE/FAILED」。
- 計劃步驟,截止日期,taymout,retrai。
- 漫遊事件並啟動補償。
- 協調員操作的相等性(命令日誌)。
- 可觀察性:在邏輯/trace/度量標準中 「saga_id」的相關性。
- 表「saga」,「saga_step」,「commands」,「outbox」。
- 「saga_id」、「business_key」、「status」、「next_run_at」上的索引。
8)編舞: 針對「雪球」的規則和保護"
活動合同:計劃和審查(Avro/Proto/JSON計劃)。
清晰的語義:「事實事件」vs「命令」。
連鎖店:發現不匹配的服務發布了「失敗」/「競爭」事件。
警報和Alerta到「無限循環」。
9)TCC: 實用細節
嘗試:具有TTL的資源儲備。
Confirm:固定,釋放臨時鎖定。
Cancel:儲備回滾(無副作用)。
Garbage collection:在TTL(等效癌癥)之後自動取消Try。
等效的Confirm/Cancel:重播是安全的。
10)示例(言語方案)-「付款和交付訂單」
1.CreateOrder(本地)→ outbox:「OrderCreated」。
2.PaymentService:「嘗試」儲備(TCC);→ 「PaymentReserved」成功,「PaymentFailed」 →失敗。
3.InventoryService:貨物儲備;缺少「InventoryFailed」 →。
4.ShippingService:創建交付插槽(可取消)。
5.如果「失敗」的任何舉動→樂團將按相反的順序觸發賠償:「CancelShipping」 → 「ReleaseInventory」 → 「PaymentCancel」。
6.如果所有人都→ 「PaymentConfirm」 → 「OrderConfirmed」。
11)編曲家的偽代碼
pseudo startSaga(saga_id, order_id):
steps = [ReservePayment, ReserveInventory, BookShipment, ConfirmPayment]
for step in steps:
res = execWithRetry(step, order_id)
if!res.ok:
compensateInReverse(steps_done(order_id))
return FAIL return OK
execWithRetry(step, key):
for attempt in 1..MAX:
try:
return step.run(key) # идемпотентно catch RetryableError:
sleep(backoff(attempt))
catch NonRetryableError:
return FAIL return FAIL
compensateInReverse(done_steps):
for step in reverse(done_steps):
step.compensate() # идемпотентно
12)可觀察性和操作SLO
Tracing:單個「saga_id」,註釋「step」,「attempt」,「decision」(運行/compensate/skip)。
度量標準:- 成功/錯誤sag(%),平均持續時間,p95/p99。
- 補償傳奇的比例,補償的最高原因。
- 隊列/outbox瀉湖,步伐回避。
- Logi/Audit:編排器解決方案、資源ID、業務密鑰。
13)測試和混亂
在每個步驟中註入錯誤:taymauts,「5xx」,業務沖突。
出局事件、重復、跳過(drop)。
長尾巴潛伏→測試截止線和補償。
質量傳奇→隊列中的WFQ/DRR和caps檢查,不存在「線頭塊」。
在DLQ的步驟和整個傳奇中重復。
14)多重性、區域、合規性
事件和sag存儲庫中的「tenant_id/plan/region」標簽。
住宅:數據/事件不會離開該地區;跨區域傳奇設計為本地傳奇+聚合事件的聯合。
優先級:VIP傳奇具有更大的配額重量;絕緣的per tenant工人。
15)售前支票清單
- 每個步驟都有明確的補償器,兩者都是相等的。
- 選擇模板:編排/編舞/TSS;說明責任範圍。
- Outbox/Inbox已實施,通過「operation_id」進行重復數據消除。
- Retrais Policy:背靠背、嘗試限制和一般的傳奇截止日期。
- 事件合同是經過驗證的,有計劃的驗證。
- DLQ和安全的重新分區配置。
- 遙測:度量,跟蹤,相關性'saga_id'。
- 操作劇本:手動cancel/force-confirm,動畫「掛起」傳奇。
- 混沌和負載測試通過,確定了SLO/錯誤預算。
16)典型錯誤
沒有補償劑或「不潔」(有副作用)。
缺少Idementity/dedup-雙重和「搖擺」狀態。
「傳奇中的傳奇」沒有明顯的界限-周期和相互鎖定。
沒有截止日期→「永恒」的傳奇和資源流失。
編曲器將狀態「存儲在內存中」,而無需穩定的支架。
沒有遙測中心的編舞→「隱形」故障。
不透明的UX:用戶看不到中間狀態。
17)快速食譜
SaaS經典:編排+outbox/inbox,指數反射,DLQ,UI中的傳奇狀態。
強資源不變量:具有TTL儲備和GC癌癥的TCC。
高體積/負載:事件編排+嚴格的冪和按鍵的度量。
多區域:本地傳奇+最終聚合;避免全球封鎖。
二.結論
傳奇是在沒有全球鎖定的分布式系統中獲得可預測的一致性的方法。清晰的補償器、等效性、可靠的交付(outbox/inbox)、定時和撤退紀律以及遙測和花花公子是確保復雜的業務流程在負載增加、服務數量和地理位置不斷增加的情況下保持可持續和可讀性的關鍵。