第四, 導入服務消費來自 Kafka 的作業請求并執行實際的導入任務。當它完成時,它可以通知 服務工作已經完成,這反過來可以通知瀏覽器。
通知已使用、已處理和完成狀態的作業
結果:
3.內存KV存儲
…用于 0 延遲數據訪問
有時我們需要為我們的應用程序進行動態而持久的配置,但我們不想為它創建一個完整的關系數據庫表。
一種選擇是使用HBase / / 為所有應用程序創建一個大的Wide Store表,其中主鍵包含標識應用程序域的前綴(例如“”)。
此解決方案運行良好,但通過網絡獲取值存在內置延遲。它比配置數據更適合更大的數據集。
另一種方法是擁有一個內存中的鍵/值緩存,它也具有持久性——Redis AOF提供了這種能力。
Kafka 以壓縮主題的形式為鍵/值存儲提供了類似的解決方案(其中保留模型確保不會刪除鍵的最新值)。
在 Wix,我們將這些壓縮主題用于內存中的 kv 存儲,我們在應用程序啟動時加載(使用)來自主題的數據。一個很好的好處(Redis 沒有提供)是該主題仍然可以被其他想要獲取更新的消費者使用。
訂閱和查詢考慮以下用例——兩個微服務使用壓縮主題來維護他們維護的數據:Wix (幫助 Wix 網站所有者管理他們的業務)使用壓縮主題來支持國家列表,以及Wix (允許安排約會和課程)維護一個“時區”壓縮主題。從這些內存中的 kv 存儲中檢索值的延遲為 0。
每個 In- KV Store 及其各自的壓縮 Kafka 主題
Wix 偵聽“支持的國家/地區”主題的更新:
消耗來自 壓縮主題的更新
當Wix 將另一個國家/地區添加到“國家/地區”主題時,Wix 會使用此更新并自動為“時區”主題添加新的時區。現在內存中的“時區” kv-store 也更新為新時區:
壓縮主題中添加了南蘇丹的新時區
我們不需要停在這里。Wix (允許 Wix 用戶管理活動門票和 RSVP)還可以使用的時區主題,并在一個國家/地區更改其時區以實現夏令時自動獲取其內存中 kv 存儲的更新。
從同一個壓縮主題消費的兩個內存中 KV 存儲
4. 安排并忘記
…當您需要確保計劃的事件最終得到處理時
在很多情況下,Wix 微服務需要根據某個時間表執行作業。
一個例子是管理基于訂閱的支付(例如訂閱瑜伽課程)的Wix 支付訂閱服務。對于每個每月或每年訂閱的用戶,必須與支付提供商進行續訂過程。
為此,Wix 自定義Job 服務調用由 服務預先配置的 REST 端點。
訂閱續訂過程發生在幕后,無需(人類)用戶參與。這就是為什么即使出現臨時錯誤(例如,第三個支付提供商不可用),續訂最終也會成功很重要。
確保此過程完全有彈性的一種方法是,作業調度程序向 服務發出頻繁的重復請求,其中當前的續訂狀態保存在 DB 中,并針對尚未到期的續訂的每個請求進行輪詢擴展。這將需要對數據庫進行悲觀/樂觀鎖定,因為同一用戶可能同時有多個訂閱擴展請求(來自兩個單獨的正在進行的請求)。
更好的方法是首先向 Kafka 發出請求。為什么?處理請求將由 Kafka 消費者按順序(針對特定用戶)完成,因此不需要用于同步并行工作的機制。
此外,一旦將消息生成到 Kafka,我們可以通過引入消費者重試來確保它最終會被成功處理。由于這些重試,請求的計劃也可能不那么頻繁。
在這種情況下,我們要確保保持處理順序,因此重試邏輯可以簡單地在具有指數退避間隔的嘗試之間休眠。
Wix 開發人員使用我們定制的消費者,因此他們只需指定一個 和適當的重試間隔來滿足他們的需求。
在某些情況下,消費者和生產者之間可能會出現延遲,以防錯誤長時間持續存在。在這些情況下,有一個特殊的儀表板用于解鎖和跳過我們的開發人員可以使用的消息。
如果消息處理順序不是強制性的,那么 中也存在利用“重試主題”的非阻塞重試策略。
配置重試策略后, 將創建與用戶定義的重試間隔一樣多的重試主題。內置的重試生產者將在出錯時生成消息到下一個重試主題,并帶有一個自定義標頭,指定在下一次處理程序代碼調用之前應該發生多少延遲。
對于所有重試嘗試都已用盡的情況,還有一個死信隊列。在這種情況下,消息被放入死信隊列,供開發人員手動查看。
這種重試機制的靈感來自這篇uber 文章。
Wix 最近開源了,很快就會對 beta 用戶開放。要了解更多信息,您可以閱讀 自述文件。
概括:
5. 交易事務中的事件
…當冪等性難以實現時
考慮以下經典電子商務流程:
我們的支付服務向 Kafka生成訂單 購買完成事件。現在服務將使用此消息并生成自己的Order 消息以及所有購物車項目。
然后所有下游服務(交付、庫存和發票)將需要使用此消息并繼續處理(分別準備交付、更新庫存和創建發票)。
如果下游服務可以依賴Order 事件僅由 服務生成一次,則此事件驅動流的實現將容易得多。
為什么?因為多次處理相同的 事件可能會導致多次交付或不正確的庫存。為了防止下游服務發生這種情況,他們需要存儲重復數據刪除狀態,例如,輪詢一些存儲以確保他們之前沒有處理過這個 Order Id。
這通常使用常見的數據庫一致性策略來實現,例如悲觀鎖定和樂觀鎖定。
幸運的是,Kafka 為這種流水線事件流提供了一個解決方案,其中每個事件只處理一次,即使服務有一個消費者-生產者對(例如 ),它既消費一條消息又產生一條新消息。
簡而言之,當服務處理傳入的 事件時,它需要將 事件的發送包裝在生產者事務中,它還需要發送消息偏移量(以允許 Kafka 代理跟蹤重復消息) .
此事務期間產生的任何消息僅在事務完成后對下游消費者(庫存服務)可見。
此外,基于 Kafka 的流程開始時的支付服務生產者必須變成一個冪等生產者——這意味著代理將丟棄它產生的任何重復消息。
有關更多信息,您可以觀看我關于Kafka 中的 once 語義的簡短介紹性演講
6. 事件聚合
…當你想知道一整批事件已經被消費了
在將聯系人導入 Wix CRM 平臺的業務流程。后端包括兩個服務。提供 CSV 文件并向 Kafka 生成作業事件的作業服務。以及使用和執行導入作業的聯系人導入器服務。
讓我們假設有時 CSV 文件非常大,將工作負載拆分為較小的作業更有效,每個作業中要導入的聯系人更少。這樣網易郵箱大師服務器設置怎么填,可以將工作并行化到 服務的多個實例。但是,當導入工作被拆分為許多較小的工作時,您如何知道何時通知最終用戶所有聯系人都已導入?
顯然,已完成作業的當前狀態需要持久化,否則內存中已完成作業的記帳可能會丟失到隨機的 pod 重啟。
在不離開 Kafka 的情況下保持這種會計處理的一種方法是使用 Kafka 。這種話題可以認為是一個流式KV存儲。
在我們的示例中, 服務(在多個實例中)將使用帶有索引的作業。每次完成處理某個作業時,它都需要使用 Job 事件更新 KV 存儲。這些更新可以同時發生,因此可能會發生潛在的競爭條件并使作業完成計數器無效。
KV Store 為了避免競爭條件, 服務會將完成事件寫入 類型的Jobs--Store 。
原子存儲確保所有作業完成事件將按順序處理。它通過創建一個“”主題和一個壓縮的“store”主題來實現這一點。
順序處理
在下圖中,您可以看到原子存儲如何以 [ Id]+[total job count] 作為鍵生成每個新的導入作業完成的“更新”消息。通過使用key,我們可以依靠 Kafka 始終將特定 的“更新”放在特定分區中。
接下來,作為 store 一部分的消費者-生產者對將首先監聽每個新更新,然后執行 用戶請求的“命令”——在這種情況下,將已完成作業的數量從以前的值。
端到端更新流程示例 讓我們回到 服務流程。一旦這個服務實例完成了一些作業的處理,它會更新 Job- (例如網易郵箱大師服務器設置怎么填, Job 3 of Id YYY 已經完成):
Store 將向 job-- 主題生成一條新消息,其中 key = YYY-6 和 Value — Job 3 。
接下來, Store 的消費者-生產者對將使用此消息并增加 KV Store 主題的 key = YYY-6 的已完成作業計數。
Once 請注意,處理“命令”請求必須恰好發生一次,否則完成計數器可能不正確(錯誤增量)。為消費者-生產者對創建一個 Kafka 事務(如上面的模式 4 中所述)對于確保會計保持準確至關重要。
值更新回調 最后,一旦已完成作業計數的最新 KV 生成值與總數匹配(例如 YYY 導入請求的 6 個已完成作業),就可以通知用戶(通過 web 套接字 — 參見第一部分的模式 3文章)關于導入完成。通知可以作為 KV 存儲主題產生操作的副作用發生 - 即調用其用戶提供給 KV 原子存儲的回調。
重要筆記:
福利