為什麼Event Sourcing是一種微服務通訊反模式 - Oliver Libutzki

banq發表於2019-06-29

事件驅動的體系結構和事件採購在過去幾年中尤其受到關注。這種趨勢是由於我們在構建具有彈性和可擴充套件性的模組化系統之後努力的結果。微服務是經常在這種情況下使用的術語。在我看來,微服務只是實現有界上下文的一種方式。模組化系統的核心是模組的邊界,如何識別這些邊界的最有前途的想法是Eric Evans的Domain Driven Design引入的戰略設計。它可以幫助您識別/發現模組的邊界(有界上下文),並描述這些有界上下文如何相互關聯的方式(上下文對映)。

領域事件是無所不在的語言的核心
雖然在Eric的書中沒有明確提到,Domain Events很好地促進了DDD概念的概念。Alberto Brandolini的Event Storming等技術將重點從技術層面轉移到組織/業務層面。我們不討論像ButtonClickedEvent這樣的UI層事件,而是關於域事件,它們是業務領域的一部分,並且由業務專家說出並理解。這些領域事件是一流的概念,提供了形成所有參與者(領域專家,開發人員......)同意的普適語言的好方法。

用於跨上下文通訊的域事件
域事件可用於促進有界上下文之間的通訊。假設我們有一個網上商店有三個有界上下文:訂單,交貨,發票。
訂單上下文的域事件是訂單接受。發票和交貨上下文對此事件的發生感興趣,因為它會導致一些內部程式啟動。

脫鉤神話
域事件的使用可幫助您開發分離的模組。域事件不關心不可用的模組,它們描述了過去發生的事情。它取決於其他模組處理事件的速度。你得到的是一個設計靈活的系統。

除了時間解耦之外,域事件還有另一個優勢,至少乍一看:Order上下文不必知道發票和發貨上下文會監聽其事件。實際上,它甚至不需要知道這些背景存在。
這很酷,但具有挑戰性的部分是事件的內容(有效載荷)。哪些資料會加入到事件中?

簡單的答案:事件溯源!
事件是有用的,所以為什麼不給它們儘可能多的權力(和責任)。這是Event Sourcing的基本理念。您不是透過更新其資料(CRUD)而是透過應用事件流來儲存聚合的狀態。

除了可以重放事件以重建應用程式狀態這一事實之外,事件源的一個重要特性是您可以免費獲得完整可靠的審計日誌。因此,當需要這樣的審計日誌時,在評估永續性策略時,必須考慮事件源。

事件溯源只是一種永續性策略嗎?
您可能想知道為什麼我直接從Domain Events到永續性策略,因為這些概念顯然在不同的層/抽象級別上工作。
......這就是我的觀點:事件溯源是由單個有界上下文做出的本地決策!這些事件不應該暴露在外面!如果另一個有界上下文使用事件溯源,則其他有界上下文不瞭解彼此的永續性策略,因為他們不知道也不關心。
如果您在全域性範圍內使用事件溯源,則需要公開共享持久層資料庫。不同的有界上下文在(關係)資料庫中共享資料是一個壞主意。

共享事件其實與共享資料庫表一樣,我們都會分享永續性細節。

有一條出路
我仍然認為域事件非常適合有界上下文之間的通訊,但這些事件不應與事件源的事件相對應

我提出的解決方案是合乎邏輯的結果:無論您是使用CRUD還是事件採購方法來實現永續性,都可以將域事件釋出到全域性事件儲存。這些域事件是您的有界上下文的公共API。如果您更喜歡在有界上下文裡面使用事件源,則將這些事件儲存在本地事件儲存中,該儲存只能從此有界上下文中訪問。

下面有兩種方式:

1. 使用已釋出語言開放主機服務:準確釋出一個域事件,其中包含其他有界上下文可能需要的所有資料。在DDD術語中,人們將其稱為具有已釋出語言的開放主機服務。

當Order發生一個事件OrderAccepted,事件的內容應該包含Order期望其他有界上下文感興趣的所有資料...所以希望Invoice和Delivery上下文找到他們需要的所有資訊。


2. Customer/Supplier:釋出多個專用域事件,每個事件使用者一個。您必須與另一方(消費者)討論每個特定的域事件,而不必定義共享模型。DDD稱這種關係為客戶/供應商。
訂單生成的事件OrderAccepted發生後,導致每個對每個有界上下文消費者釋出一個域事件:InvoiceOrderAccepted和DeliveryOrderAccepted。

我不想討論兩種選擇的利弊。我只想強調您可以自由選擇域事件的數量及其有效負載。
這是一個不容小覷的優勢,因為您可以決定如何改進Bounded Context的API,而不是致力於Event Sourcing所需的事件。

結論
將永續性細節暴露給外部世界是一種眾所周知的反模式。在談論永續性時,我們首先考慮資料庫表,但是暴露儲存在資料庫中事件(Event Sourcing)同樣也是一種反模式。
 

相關文章