2016-11-20 76 views
4

我已經閱讀Jonathan Oliver關於處理亂序事件的好消息。在CQRS讀取端處理亂序事件

http://blog.jonathanoliver.com/cqrs-out-of-sequence-messages-and-read-models/

,我們用的是出隊的消息,並把它放在一個「支持臺」,直到與前一個序列的所有消息都收到 的解決方案。當收到所有先前的消息時,我們將所有的 消息從保留表中取出,並依次通過 合適的處理程序運行。一旦所有處理程序都成功執行 ,我們將從保留表中刪除消息,並提交 更新到讀取模型。

這適用於我們,因爲該域名發佈事件並使用適當的序列號標記它們 。沒有這個,下面的解決方案 會更困難 - 如果不是不可能的話。

該解決方案使用關係數據庫作爲持久性存儲 機制,但我們沒有使用存儲引擎的任何關係方面。與此同時,所有這一切都有一個警告。 如果消息2,3和4到達但消息1從未做過,我們不會將它們中的任何一個應用於 。只有在處理消息1時出現錯誤 或者消息1以某種方式丟失時纔會發生該情況。幸運的是, 很容易糾正我們的消息處理程序中的任何錯誤,並且 重新運行消息。或者,在丟失消息的情況下,直接從事件存儲器重新構建 。

有幾個問題,特別是他如何說我們總是可以向活動商店索要失蹤事件。

  1. CQRS的寫入端是否必須公開讀取 端的服務以「請求」重放事件?例如,如果事件1不是收到的 ,而是2,3,4,我們是否可以通過 服務請求事件庫重新發布從1開始的事件?
  2. 這個服務是CQRS寫端的責任嗎?
  3. 我們如何使用它重新構建讀取模型?
+0

我們使用RabbitMq的「重試」方法,它工作正常。如果經過多次重試仍然無效 - 只需將該事件置於死信隊列中並重置序列號,以便可以正確處理更多事件。通常在您的應用程序中亂序事件的原因是什麼? – IlliakaillI

+0

我有一些會生成多個事件的特定命令。我還沒有執行任何操作,但可能會出現亂序事件。我的活動發佈者也是異步工作的。所以有可能某些事件可能無法按順序發佈。我依靠我的事件序列號來幫助我重新組合。 我會嘗試重試方法。如果你可以詳細說明一下,我可以將其標記爲答案。 –

+0

我在答案的評論部分添加了更詳細的解釋。 – IlliakaillI

回答

1

如果您有一個序列號,那麼您可以檢測當前事件發生故障的情況,例如, currentEventNumber!= lastReceivedEventNumber + 1

一旦你發現了,你只是拋出一個異常。如果您的訂閱者擁有「重試」機制,它將嘗試在一秒鐘內重新處理此事件。在這段時間內,有一個相當好的機會將會處理更早的事件並且順序將是正確的。如果無序事件很少發生,這是一個解決方案。

如果您經常遇到這種情況,您需要實現全局鎖定機制,這將允許某些事件按順序處理。 例如,我們在MSSQL中使用sp_getapplock來實現某些情況下的全局「臨界區」行爲。當分佈式應用程序的多個部分需要的不僅僅是一個簡單的鎖時,Apache ZooKeeper提供了一個處理更復雜場景的框架。

+0

我正在研究某些多人遊戲如何處理這種情況。遊戲內置高速緩存,持續大約100ms。在應用事件之前等待100ms,以防事件丟失。由於潛在的可伸縮性問題,我有點猶豫是否使用任何鎖。順便說一句,你如何向活動商店詢問實施中的遺漏事件? –

+0

如果你想使這個系統健壯,你必須非常小心聚合端的各種緩存。如果你的應用程序突然失敗會發生什麼?根據我的經驗,使用緩存事件的方法不會擴展。在我們的業務案例中,我們構建了分佈式24/7容錯服務器,這意味着您必須在單獨的物理機器上至少有2個聚合器進程實例。如果你想避免裂腦情況 - 你必須考慮有3個獨立的實例並行運行。 – IlliakaillI

+0

>>您如何在事件存儲庫中查找您的實施中遺漏的事件? 好吧,我們使用rabbitmq,後來改用天藍色的服務總線。這兩項服務都提供了交付保證的功能。你基本上知道隊列服務,你的事件在聚合器端的事務結束時已經被成功處理。 – IlliakaillI

0

你在這裏描述的是事件採購(ES)。通過命令模型將發出的事件存儲到持久存儲器 通過事件類型,命令模型ids(聚合根ID),命令模型類型(聚合根類型)重播存儲的事件。有ES的優勢。您甚至可以稍後重播這些事件以生成新類型的查詢模型。 使用ES方法也可以用於具有UnitOfWork範圍的應用程序事務。在提交時,發出的事件被持久化並分發給事件監聽器(QM維護服務)。提交階段的驗證應該包含通過db中的序列號檢查併發訪問。

+0

不幸的是,這並不回答任何發佈的問題。我之前已經使用ES實現了CQRS,但是這個問題是特定於亂序/丟失事件的上下文的。 –

+0

不合時宜的情況很容易通過延遲交貨解決。如果您檢測到超出序列信息,您將延遲交付。但是交付本身應該是一致的。你選擇什麼樣的信息傳遞方式?至少一次,至少一次或者正好一次。消息傳遞由基礎設施(RabbitMQ,Kafka)處理?公式,卡夫卡將確保訂單主題交付給每個組。甚至可以持續消息定義的時間,因此消費者可以離線幾個小時,消息將被傳遞。 – hellxcz

+0

我使用RabbitMQ,它保證「至少一次」交付。所以消息冪等性也必須在事件處理器上實現。 –