3

依賴比方說,我們有一個寫模型(域)生成兩個事件:域事件因果關係與事件採購和CQRS

  • CarrierAdded(...)
  • BusConnectionCreated(載體。 ..)

載波和總線連接類是(部分)單獨的聚合。 BusConnection分配給運營商幷包含其CarrierId(單獨的集合僅通過id引用)。

在正常的命令和事件流程中,在寫入模型和讀取模型中,一切都很好,但是當我們想從頭開始重新構建/添加新的讀取模型時,問題就出現了。

許多人建議(例如akka持久性庫)事件存儲中的每個聚合事件存儲事件。當denormalizer要求回覆事件時,他會從每個聚合中獲取兩個獨立的事件流。問題是來自不同集合的一些事件需要按照它們添加到事件存儲庫的順序進行回覆。這意味着我們需要某種因果關係/部分排序。

最後我的問題:

  • 我應該重新思考自己的域的設計(壞合計邊界?)或
  • 我需要只執行部分排序?

如果是後者,那麼最有效的方法是什麼?

  • Global counters?似乎不可擴展。
  • 某種矢量時鐘?
  • 在denormalizer出現時檢測這些問題嗎?例如。我們得到了CarrierId,我們沒有這個ID的CarrierAdded事件還,所以我們藏匿的事件和等待預期的一個第一
  • 在回放模式中處理事件方面介紹一些訂單?例如。所有與運營商有關的事件首先是BusConnection相關事件?

回答

5

不,國際海事組織您的設計是完美的,很常見。你必須以某種方式強制執行部分命令。

我不熟悉的阿卡的持久性,但有些事件存儲由記錄事件的時間戳實現部分排序和重播事件的時間戳的順序。有些事件存儲確實使用全局計數器,例如底層數據庫是關係數據庫,系統不需要擴展時 - 數據庫提供的序列號在這裏工作正常。

時間戳當然只能保證排序到一個給定的粒度,通常爲1ms。在某些情況下,這已經足夠,例如,如果您可以確保CarrierAdded是從不發生與BusCarrierAdded在同一毫秒內發生。

至於可擴展性,確保向外擴展確實是你的情況的問題,公共汽車交通系統似乎並沒有被「大規模」 ...如果您可以使用單個主數據庫服務器,則事件流中的事件序列號是實現所需部分排序的直接可靠方法。序列號可能因爲「交織」/平行提交而失敗,因此您需要確保在添加BusCarrier之前始終將CarrierAdded事件添加到事件存儲庫/數據庫中,但在您的方案中似乎很可能。

如果您確實需要向外擴展並且這兩個事件可能會在相同的毫秒內出現,您的確必須在處理程序中檢測到問題並使用非規範化。這聽起來比它更難,因爲它可以通過一個非常簡單的狀態機輕鬆實現。喬納森奧利弗在傳奇的背景下有blogged about state matchines here,但這個原則也適用於這裏。

+0

爲了打破密切關係,關於事件和命令的「因果關係」呢?實質上,一種衡量副作用樹中命令/事件的「深度」的方法,根源於在步驟0開始級聯的任何外部/調度/用戶觸發命令。當您有兩個具有相同時間戳的項目時,通常先處理具有較低計數器的項目即可,即使它們實際上並不相關。 – Darien

+0

是的,這也可以起作用(但是我想這可能很難實現或者給開發者帶來一些負擔)。 –