事件驅動內核
什麼是Event-Driven內核
Event-Driven內核(EDC)是體系結構的「脊柱」,其中業務事實被捕獲並作為不可變事件傳播,其余功能(閱讀,集成,分析,緩存,符號化)建立在這些事件流之上。內核指定事件合同,交付規則以及順序/相容性不變性,從而提供較弱的連通性和可擴展性。
關鍵思想:首先寫出事實(內核),然後將其獨立豐富並投影到所需的模型中。這會降低連通性並增加對部分故障的抵抗力。
EDC的目標和屬性
事實的真實性:每個事件都是「發生了什麼」的不可改變的記錄。
連通性弱:生產者不認識消費者;系統擴展-增加訂戶。
擴大規模:按政黨/拓撲水平增長,獨立消費者。
可觀察性和審計:端到端ID,可重復性,可重復性和可重復性。
受控演變:方案版本,兼容性,可執行性。
體系結構組件
1.總線/活動經紀人:Kafka/NATS/Pulsar/SNS+SQS-頻道,派對,回避。
2.電路註冊表:JSON Schema/Avro/Protobuf,用於兼容性和進化。
3.Outbox/CDC路徑:原子事實固定+發布沒有「雙重記錄」。
4.投影/讀取(CQRS):用於快速查詢的實例化視圖。
5.傳奇/編排:通過事件/命令協調長壽過程。
6.豐富:單獨的「.enriched」/「derived」拓撲,對關鍵路徑沒有影響。
7.天文可用性:跟蹤、邏輯、事件和滯後指標。
事件模型
事件類型
域事件: 業務事實('payment.authorized`, `kyc.approved`).
Integration Events:面向外部系統(穩定,變化緩慢)。
更改數據捕獲(CDC):技術記錄更改(用於遷移/集成)。
審計/電信:演員行動,安全,SLA。
強制屬性(內核)
json
{
"event_id": "uuid",
"event_type": "payment. authorized. v1",
"occurred_at": "2025-10-31T11:34:52Z",
"producer": "payments-service",
"subject": { "type": "payment", "id": "pay_123" },
"payload": { "amount": 1000, "currency": "EUR", "method": "card" },
"schema_version": 1,
"trace_id": "abc123",
"partition_key": "pay_123"
}
建議:'event_id'是全局唯一的,'partition_key'設置實體的順序,'trace_id'提供相關性。
交付語義和冪等
On-Least-once(許多經紀人默認):消費者必須保持平均水平。
最多:只有次要遙測才能接受。
Exactly-once:通過交易/等價密鑰/湖泊在線程和存儲級別實現(更貴,需要充分的理由)。
消費者的相容性模板
「event_id」/'(event_id,consumer_id)的dedup表與TTL ≥拓撲。
Upsert代替insert;在「sequence」/「occurred_at」上轉換投影。
交易中的操作:標記「看到」+狀態變化。
順序和分組
保證黨內秩序。
選擇「partition_key」以便將單個聚合實體的所有事件分成一個部分(「user_id」,「payment_id」)。
避免「熱鍵」:如果要分配負載,則使用鹽/小鍵哈希。
模式和演變
Additive-first:新的可選字段,禁止在沒有主要版本的情況下更改類型/語義。
兼容性:方案註冊表中的BACKWARD/FORWARD;CI阻止不兼容的更改。
命名: "域。action.v{major}` (`payment.authorized.v1`).
遷移:並行發布「v1」和「v2」對,提供雙輻射(通過outbox進行雙寫入),過渡後拍攝「v1」。
Outbox и CDC
Outbox(推薦用於事務性服務)
1.在一個DB事務中:我們將域記錄和事件存儲在outbox中。
2.背景公關人員閱讀outbox,發布到經紀人,標記「發送」。
3.保證:跌倒時沒有「損失」事實,沒有同步。
CDC (Change Data Capture)
適用於現有系統/遷移;來源-DB復制日誌。
需要過濾/重新編碼到域事件(不要向外廣播「原始」表)。
CQRS和投影
命令更改狀態(通常是同步的),事件生成投影(異步)。
投影是針對查詢(搜索,列表,報告)設計的,並由訂戶更新。
時間同步是規範:顯示穩定的UX(「數據將在幾秒鐘內更新」)。
傳奇: 流程協調
編排:一個協調員發送命令並等待事件。
編舞:參與者對彼此的事件做出反應(更簡單,但需要合同紀律)。
規則:明確的補償和超時,可重復的步驟,相同的處理程序。
可觀察性
Trace/Span:在生成事件時,通過標題來推動「trace_id」/「span_id」。
指標:消費者脫落,發布/消費速度,死信率,重復數據消除比例。
DLQ/parking lot:不合時宜的消息-成一個單獨的標有alert的標題;確保重新整理。
安全性和合規性
數據分類:內核僅包含所需的最小PII/findans(反金字塔模型),細節包含在富集中。
關鍵屬性的簽名/散列,完整性控制。
按主題/控制器(IAM/ACL)對權限進行飛行加密,並進行恢復。
回避政策和遺忘權:為每個拓撲明確定義。
性能和可持續性
Backpressure:消費者有競爭限制,經紀人有配額/限制。
Batch處理和壓縮:分組記錄以降低開銷。
帶有抖動器和DLQ的回程代替無休止的嘗試。
反彈韌性:在交易/外部存儲離場,用快門加速冷啟動。
典型事件模板
支付核心
`payment.initiated.v1` → `payment.authorized.v1` → `payment.captured.v1` → `payment.settled.v1`
免責聲明: '付款。declined.v1`, `payment.refunded.v1`
派對: 「payment_id」
SLA:核心差≤ 2 s p95;消費者的偶然性是強制性的。
CUS/驗證
`kyc.started.v1` → `kyc.document.received.v1` → `kyc.approved.v1`/`kyc.rejected.v1`
PII-最小;文檔詳細信息-在'kyc中。enriched.v1'限制訪問。
審計/安全
`audit.recorded.v1'具有「actor」,「subject」,「action」,「occurred_at」,「trace_id」屬性。
持續撤回/歸檔;增強的完整性(WORM存儲)。
反模式
Fat Event:不需要負擔過重的薪水,PII泄漏。
通過事件隱藏的RPC: 等待同步響應「在這裏和現在。」
原始CDC向外:與DB方案的緊密連接。
消費者沒有偶然性:配音會導致雙重副作用。
一個「全部」的常見拓撲:利益沖突,有問題的秩序,復雜的演變。
逐步實施EDC
1.域映射:突出顯示關鍵聚合和生命周期。
2.事件目錄:標題,含義,不變量,必填字段。
3.圖和註冊表:選擇格式,啟用兼容性規則。
4.Outbox/CDC:為每個制作人定義發布事實的機制。
5.分期:選擇密鑰並評估熱鍵/重寫。
6.相似性:消除重復模式+消費者事務性。
7.投影:定義實例化模型和更新SLA。
8.天文可用性:跟蹤、瀉湖、DLQ、Alertes。
9.安全/PII:數據分類、加密、ACL。
10.進化論海德:版本政治,消除裂痕,雙寫作以進行遷移。
生產支票清單
- 每個事件都有'event_id'、'trace_id'、'occurred_at'、'partition_key'。
- 註冊表中的方案,包括兼容性檢查。
- 實現並測試了消費者的水平。
- 已將DLQ/parking lot和Alerta配置為發布/消費錯誤。
- 投影以可接受的時間從邏輯(replay)中重建。
- 限制使用PII;內核中的最低工資。
- 對滯後/交貨的SLA進行了測量,並在行車記錄儀上可見。
- 有計劃遷移事件版本和刪除記錄窗口。
FAQ
EDC與「簡單輪胎」有何不同?
核心不僅是經紀人,而且是事件契約,順序/相等性規則,進化過程和可觀察性。
只能在CDC上構建嗎?
CDC適用於集成/遷移,但是域事件更清楚地表達了意義,並且更穩定地經歷了DB的變化。
如何保持一致?
接受事件一致性並設計其下方的UX/過程(刷新,撤銷,補償指標)。
什麼時候需要exactly-once?
很少:當加倍是嚴格不可接受的,無法補償。更常見的是,at-least-once+等效性就足夠了。
底線
Event-Driven內核將業務事實流轉變為系統的可靠基礎。明確的事件合同,交付紀律和可觀察性提供了可擴展性,穩定性和進化速度-沒有脆弱的同步鏈接和變化中的「風暴」回歸。