GH GambleHub

事件體系結構

事件體系結構(EDA)

1)什麼是事件和為什麼EDA

事件是在域中已經發生的不變事實(「PlayerVerified」,「PaymentCaptured」)。EDA圍繞這些事實的發布和對它們的反應來構建集成:
  • 服務連通性薄弱,
  • 獨立地擴大消費者的規模,
  • 放置/重構投影,
  • 透明審計。

EDA不會取消同步API-它通過將跨服務依賴項帶到異步層來補充它們。


2)事件類型

域:有意義的業務事實(OrderPlaced, BonusGranted)。
集成:外部系統的「快照「/更改(UserUpdated, WalletBalanceChanged)。
技術:生命周期和遙測(Heartbeat,PipelineFailed)。
命令(不是事件,但附近):「做X」指令(CapturePayment)。

建議:域事件-主要事件;通過針對特定消費者的投影來形成集成。


3)事件和計劃合同

Схема: Avro/Protobuf/JSON Schema + Schema Registry;兼容性策略:「BACKWARD」用於消費者進化,「FULL」用於關鍵主題。
CloudEvents (id, source, type, time, subject, datacontenttype)-統一標題。
強制性元數據:「event_id」(ULID/UUID),「occurred_at」,「producer」,「schema_version」,「correlation_id」/「causation_id」,「idempotency_key」。
轉化:僅附加字段,禁止重命名/語義斷裂;新類型-新主題/類型。

示例(Avro,片段):
json
{
"type":"record","name":"PaymentCaptured","namespace":"events.v1",
"fields":[
{"name":"event_id","type":"string"},
{"name":"occurred_at","type":{"type":"long","logicalType":"timestamp-micros"}},
{"name":"payment_id","type":"string"},
{"name":"amount","type":{"type":"bytes","logicalType":"decimal","precision":18,"scale":2}},
{"name":"currency","type":"string"},
{"name":"player_id","type":"string"}
]
}

4)交付,順序和一致性

在默認情況下,需要處理程序的冪等→。
順序:在聚會(Kafka)或隊列(RabbitMQ)中得到保證,但在回避時可能會受到幹擾;事件密鑰必須反映順序域顆粒(例如「player_id」)。
一致性:金錢/貸款-僅通過雜誌/傳奇/報銷;避免LWW。

閱讀模型:投影和緩存可以是事件-顯示「正在進行更新」……並使用RNOT策略進行嚴格的路徑。


5) Outbox/Inbox и CDC

Outbox:該服務將事實寫入其DB,並在單個事務中寫入outbox表→用戶發布到總線。
收件箱:消費者保留「event_id」與處理結果進行重復數據消除。
CDC(更改數據捕獲):從DB (binlog/WAL)到總線的更改流,用於在不更改應用程序的情況下構建集成。
Idempotency:通過「idempotency_key」/「event_id」處理,在固定之前不要改變外部世界。


6) CQRS и Event Sourcing

CQRS:共享寫模型和讀取投影;投影是由事件構成的,可能會滯後。
Event Sourcing:聚合狀態=其事件的卷積。優點:全面審計/重播;缺點:遷移/計劃/狙擊的復雜性。
實踐:ES-不在任何地方,而是歷史和補償重要的地方;CQRS幾乎總是在EDA中。


7)傳奇: 編排和編舞

編排:協調員發送命令並等待事件響應;方便於復雜的流程(KYC→Deposit→Bonus)。
編舞:服務部門對彼此的事件做出反應;更容易但更難追蹤。
始終定義補償和截止步驟。


8)拓撲設計(Kafka/RabbitMQ)

Kafka

Topik per域事件: 'payments。captured.v1`, `players.verified.v1`.

派對鍵:「player_id」/「wallet_id」-順序重要的位置。
`replication.factor=3`, `min.insync.replicas=2',prodewser' acks=all'。
Retention:按時間(例如7-90天)和/或匹配(按鍵的最後狀態)。
背靠背的復古和DLQ拓撲。

RabbitMQ

Exchanges: `topic`/`direct`, routing key `payments.captured.v1`.

對於廣泛的粉絲,「topic」+排隊數次;對於RPC/命令-單獨的隊列。
HA的Quorum Queues;用於中繼的TTL+dead-letter交換。


9)可觀察性和SLO EDA

SLI/SLO:

端到端延誤(occurred_at →處理):p50/p95/p99。
Lag/age:消費者滯後(Kafka消費者lag,Rabbit backlog age)。
通過出版/處理。
DLQ-rate和重復比例。
業務運營成功(例如,「存款確認≤ 5 c」)。

實踐:
  • 通過「trace_id」/「correlation_id」(OTel)關聯事件。
  • 來自→軌跡度量的實例(exemplars)。
  • 帶有burn-rate alertes的dashbords 「Producer→Broker→Consumer」。

10)Replay,重建和backfill

重建投影/修復錯誤:賽車進入新的投影/內空,然後切換讀數。
重組:法律/業務要求(GDPR/PCI);敏感字段-加密和/或令牌化。
Backfill:一次性主題/隊列,明確的RPS限制,以免扼殺prod。


11)安全和合規性

TLS transit,mTLS面向內部客戶。
授權:per-topic/per-Exchange ACL;multitenancy通過namespace/vhost。
PII:將事件中的字段最小化;envelope元數據是分開的,有效載荷在需要時加密。
審核事件訪問,禁止「萬能」密鑰。
還原策略和刪除權限(GDPR):要麼存儲數據引用,要麼在投影中存儲tombstone事件和刪除。


12)在EDA進行測試

合同測試:消費者驗證他們對計劃的期望(消費者駕駛)。
Replay測試:通過新的處理程序/模式版本運行歷史樣本。
混沌情景:經紀人的延遲/損失,節點下降,消費者積壓→ SLO仍然存在。
CI中的Smoke:臨時主題上的簡短端到端管道。


13)遷移「CRUD集成→ EDA」

1.識別域事實。
2.將outbox引入源服務。
3.發布最小域事件並連接1-2投影。
4.逐步禁用點同步集成,代之以訂閱。
5.輸入Schema Registry和兼容性策略。
6.將事件擴展到僅附加字段;切片-僅通過新類型。


14)反模式

事件=「DTO API」(過於胖,取決於內部模型)-破壞消費者。
缺少Schema Registry和兼容性-「脆弱」集成。
從代碼中發布並寫入DB不是atomaran(不是outbox)-丟失事件。
「無處不在」-無利可圖的高價;更好-least-once+等效性。
一個「通用」黨派鑰匙→熱門黨派。
直接回放到投影中-打破在線SLO。


15)實施清單(0-45天)

0-10天

定義域事件及其密鑰(順序顆粒)。
部署Schema Registry並批準兼容性策略。
將outbox/inbox添加到1-2服務中;最小的CloudEvents-envelope。

11-25天

輸入retry/DLQ、backoff、處理程序等。
Dashbords:lag/age/end-to-end;burn-rate alerta。
事件文檔(目錄),所有者以及通過模式評論的過程。

26-45天

首次投影/重建;runbook中繼和backfill。
安全策略(TLS,ACL,PII),續集,GDPR程序。
定期為經紀人和消費者提供混沌和遊戲日。


16)成熟度量

100%的域事件由電路描述並註冊。
Outbox/inbox涵蓋了所有Tier-0/1制作人/用戶。
SLO:目標範圍內的p95端到端延遲和消費者lag ≥ 99%。
在沒有市區的情況下,Replay/Backfill是可行的。有一個經過驗證的運行手冊'和。
轉化:新領域-無碎片;老消費者不會倒下。
安全性:TLS+mTLS、ACL每主題、訪問日誌、PII/重建策略。


17)迷你嗅探

Kafka Producer(可靠的出版物,想法):
properties acks=all enable.idempotence=true max.in.flight.requests.per.connection=1 compression.type=zstd linger.ms=5
消費者處理程序(等效性,偽代碼):
python if inbox.contains(event_id): return # дедуп process(event)            # побочные эффекты детерминированы inbox.commit(event_id)        # atomically with side-effect commit_offset()
RabbitMQ Retry通過DLX(想法):
  • `queue: tasks` → on nack → DLX `tasks.retry.1m'(TTL=60 s)→返回「tasks」;接下來是「5 m/15 m」。

18)結論

EDA將集成轉變為具有明確合同和管理一致性的業務事實流。構建基礎:電路+註冊表,outbox/inbox,階鍵,等效處理程序,SLO和可觀察性,安全重構和繼電器。然後,事件將成為你擴大規模,分析和新奇觀的「真理之源」-沒有脆弱的聯系和夜間遷移。

Contact

與我們聯繫

如有任何問題或支援需求,歡迎隨時聯絡我們。我們隨時樂意提供協助!

開始整合

Email 為 必填。Telegram 或 WhatsApp 為 選填

您的姓名 選填
Email 選填
主旨 選填
訊息內容 選填
Telegram 選填
@
若您填寫 Telegram,我們將在 Email 之外,同步於 Telegram 回覆您。
WhatsApp 選填
格式:國碼 + 電話號碼(例如:+886XXXXXXXXX)。

按下此按鈕即表示您同意我們處理您的資料。