標題:為什麼事件溯源是一種微服務通訊反模式

發表:真實

描述:這篇文章描述了合理的事件溯源用例,並提供了微服務之間通訊的替代方案。

封面圖片:https://github.com/OLibutzki/blog/raw/master/water-4230596_1920.jpg

標籤: 事件溯源, 領域驅動設計, 領域事件


一般而言,事件驅動架構,特別是事件溯源,在過去幾年中獲得了廣泛關注。這種趨勢是由於我們努力建構具有彈性和可擴展性的模組化系統而引起的。微服務是在這種情況下經常使用的術語。在我看來,微服務只是實現有界脈絡的一種方法。模組化系統的核心是模組的邊界,而如何辨識這些邊界最有前途的想法是 Eric Evans 的領域驅動設計中引入的戰略設計。它可以幫助您辨識/發現模組及其邊界(有界上下文),並描述這些有界上下文相互關聯的方式(上下文映射)。

注意:我會預設某些術語的一些預知,因為我不想第一千次解釋它們。我決定連結到microservices.io維基百科Martin Fowler 的 Bliki的解釋,因此,如果您對自己的知識感到不舒服,則可以更深入地研究某個主題。

領域事件作為通用語言的核心

儘管在 Eric 的書中沒有明確提及,但領域事件很好地促進了 DDD 概念的發展。像 Alberto Brandolini 的事件風暴這樣的技術將事件的焦點從技術層面轉移到組織/業務層面。我們不討論一些 UI 層事件,例如ButtonClickedEvent ,而是討論領域事件,它們是業務領域的一部分,並由業務專家說出和理解。這些領域事件是一流的概念,並提供了一種形成所有參與者(領域專家、開發人員…)都同意的通用語言的好方法。

用於跨界通訊的領域事件

領域事件可用於促進有界上下文之間的溝通。假設我們有一家具有三個限界上下文的線上商店:訂單、交貨、發票。

訂單上下文的網域事件是訂單已接受。發票和交付上下文對此事件的發生感興趣,因為它會導致一些內部流程啟動。

脫鉤神話

使用領域事件可以幫助您開發解耦的模組。模組可能會暫時離線。領域事件不關心不可用的模組,它們描述過去發生的事情。這取決於其他模組處理事件的速度。您得到的是一個設計上具有彈性的系統。

除了時間解耦之外,領域事件還具有另一個優勢,至少乍看之下是這樣:

Order 上下文不必知道 Invoice 和 Delivery 上下文會偵聽其事件。實際上它甚至不需要知道這些上下文的存在。

這很酷,但具有挑戰性的部分是事件負載。哪些資料放入事件中?

簡單的答案:事件溯源!

事件很有用,所以為什麼不賦予它們盡可能多的權力(和責任)。這就是事件溯源的基本思想。您不會透過更新資料 (CRUD) 而是透過套用事件流來儲存聚合的狀態。

除了您可以重播事件以重建應用程式狀態之外,事件來源的一個重要功能是您可以免費獲得完整且可靠的審核日誌。因此,當需要這樣的稽核日誌時,在評估持久性策略時一定要考慮事件溯源。

事件溯源只是一種持久性策略嗎?

您可能想知道為什麼我從領域事件直接轉向持久化策略,因為這些概念顯然適用於不同的層/抽象層級。

……這就是我的觀點:事件溯源是由單一限界上下文做出的本地決策!這些事件不該向外界曝光!其他限界上下文則不知道彼此的持久化策略,因此它們不知道也不關心另一個限界上下文是否使用事件溯源。

如果您在全球範圍內使用事件溯源,則會暴露您的持久層。

您的持久性將成為您的公共 API。每次限界上下文調整其持久性資料時,我們都必須處理公共 API 變更。

我很確定每個人都同意,由於開發和執行時耦合,不同的限界上下文共享(關係)資料庫中的資料是一個壞主意。但差別在哪裡呢?

空無一人。我們是否共享事件或資料庫表並不重要。在這兩種情況下,我們都會分享持久性詳細資訊。

有出路

我仍然認為領域事件非常適合限界上下文之間的通信,但這些事件不應與用於事件溯源的事件相對應。

我提出的解決方案是合乎邏輯的結果:無論您使用 CRUD 還是事件溯源方法來實現持久性,您都可以將領域事件發佈到全域事件儲存。這些領域事件是有界上下文的公共 API。如果您喜歡在限界上下文中使用事件溯源,則可以將這些事件儲存在本機事件儲存中,該儲存只能從此限界上下文存取

選擇的自由

在公共 API 中擁有專用領域事件可讓您決定如何對這些事件建模。您不受事件來源事件預先定義的佈局的限制。

對於每次發生的“現實世界事件”,您有兩個選擇:

使用已發布語言的開放主機服務

準確發布一個網域事件,其中包含其他限界上下文可能需要的所有資料。在 DDD 術語中,我們將其稱為具有已發布語言的開放主機服務。

使用已發布語言的開放主機服務

現實世界事件Order Accepted的發生會導致發布一個網域事件OrderAccepted 。此事件的有效負載包含 Order 期望其他限界上下文感興趣的所有資料...因此希望 Invoice 和 Delivery 上下文找到它們所需的所有資訊。

客戶/供應商

發布多個專用領域事件,每個事件使用者一個。您必須與另一方(消費者)討論每個特定的領域事件,而不必定義共享模型。 DDD 將這種關係稱為客戶/供應商。

客戶/供應商

現實世界事件Order Accepted的發生會導致每個消費限界上下文發布一個網域事件: InvoiceOrderAcceptedDeliveryOrderAccepted 。每個領域事件都包含消費上下文所請求的資料。

我不想討論這兩種選擇的優缺點。我只是想強調一下,您可以自由選擇領域事件的數量及其有效負載。

這是您不應低估的巨大優勢,因為您可以決定如何發展有界上下文的 API,而不必致力於事件溯源所需的事件。

結論

向外界公開持久性細節是一種眾所周知的反模式。在談論持久性時,我們首先想到的是資料庫表,但我解釋了為什麼用於事件來源的事件只是持久性資料的另一種方式。因此,暴露這些事件也是一種反模式。

{% 推特 784691906005635072 %}

如果以適當的(本地)方式使用事件溯源,它會非常強大。乍一看,它似乎是事件驅動架構的靈丹妙藥,但如果您深入研究,您會意識到它可能會引導您進入緊密耦合(分散式)系統……當然,這不是您的目標。

參考

除了我的個人經驗之外,我還從不同的摘要和會議演講中獲得了許多靈感。我想重點介紹 Eberhard Wolff 的演講《基於事件的架構以及使用 Kafka 和 Atom 的實現》 。特別是事件溯源事件中有什麼?與本博文的上下文高度相關。我選擇的線上商店範例是受到這次演講的啟發。

如果您想獲取更多訊息,還可以查閱其他一些資源:


原文出處:https://dev.to/olibutzki/why-event-sourcing-is-a-microservice-anti-pattern-3mcj


共有 0 則留言