當前位置:
首頁 > 最新 > 領域事件及事件匯流排EventBus使用實踐

領域事件及事件匯流排EventBus使用實踐

@大鵬開源:別看我有點萌,我可以秒變大鵬

地址:https://github.com/dapeng-soa


DDD 與領域事件

在過去的 30 多年,就已經有領域建模和設計的思潮,Eric Evans將其定義為領域驅動設計(Domain-Driven Design,簡稱DDD)。領域模型是領域驅動的核心,而領域事件又作為領域模型中的重要模塊,解決了開發者日常開發中的很多痛點,如降低代碼耦合,增強拓展性。

領域模型不是高大上的東西,所有的領域模型抽象都來自於具體的業務,而脫離業務需求的應用設計是沒有任何價值的。

在Today的新零售架構中:門店、採購、訂單、供應商、物流、商品、台賬等等都是應用設計中的不同領域模型,當然還存在很多子域模型,而對於技術人員來說,這些抽象出來的領域,就代表應用架構存在若干子系統。

系統與系統間會存在很多關聯。比如說A領域「發生某件事情」、「當什麼產生變化的時候」、「如果什麼狀態變更」...,都將可能成為B領域所要關心的事件。


事件匯流排

關心一件事,便會收集這件事情相關的信息,而這些都將會轉換為消息流,在訂閱這件事情的領域間傳播。我們將發出事件通知的一方稱為發送者(Publisher),關心事件的一方稱為訂閱者(Subscriber)。

以上eventbus示意圖大致流程是這樣的:

服務介面觸發事件。

eventbus 分發事件,如果存在領域內訂閱者,直接分發到指定訂閱者,再將事件消息存庫定時發送至 kafka ;如果不存在領域內訂閱者,事件消息直接存庫並定時發送 kafka。

消息在發送成功以後會被清除,為了保證事務的一致性,建議事件db共享業務數據源。

訂閱者只需要訂閱事件雙方規約好的 topic 和事件類型就可以命中需要的事件消息。


引入事件的依據

很多業務場景下,我們可能需要在某件事情完成後,根據業務完成狀態來做業務路由。

比如說商品領域的的變價審核業務,在商品變價審核通過之後,對應的商品價格也隨之生效;價格的變動可能會引起採購、供應商、門店等領域相應作出調整。

而我們在代碼中通常這樣去描述與以上類似的業務:

從上面可以看出,當主線業務遭遇某個狀態時,需要第三方系統作出應對。若我們在主線任務中加入了較長的代碼甚至引入別人的 api ,這會使得單個業務變的臃腫、過度耦合、不易閱讀,這時領域事件可以幫助我們更加優雅的解決這個問題。

當引入事件後,do A 將變成了 send eventA。


事件匯流排實踐

在 today 中台服務團隊的各領域實踐中,為了給第三方系統和本部門的業務開發人員提供一致性的開發體驗,我們將事件匯流排從dapeng的框架中剝離出來, 單獨提供了一套類庫用於實現事件的發布以及訂閱。



在業務資料庫加入一張如下結構數據表,作為事件消息的暫存隊列和事件發送狀態存儲表。

在具體開發中實現事件發送與訂閱需要四步:

定義事件結構體;

在服務介面方法中聲明待發布的事件;

通過EventBus發布事件;

通過EventBus接收事件。

下面以商品變價審核的狀態變更為例,具體說明一下每個步驟。


1.事件收發雙方共同協定事件消息的內容, 一個領域的所有消息定義都在同一個獨立的idl文件中, 這個idl文件應該放在發布者的API包中。

2.事件對象需要定義一個事件 id (建議通過分散式取號服務來獲取), 訂閱者可以自己決定是否需要用這個事件 id 來做消息的冪等處理。


秉承代碼及文檔一致的理念,所有的服務都會在統一的文檔站點進行開放展示,每個服務和介面的描述,包括出入參都一目了然。我們在服務介面方法裡面聲明需要發布的事件,這些事件清單將會在文檔站點對應的服務方法中得到展示,減少開發人員的溝通成本。

在文檔站點方法上效果如下:

顯示獨立的事件清單

註:若想要了解更多有關文檔站點的內容,請留意後期的 dapeng 文檔站點專題。


定義事件發布任務idl

為發布任務服務提供以下實現模版


所有的事件消息,最終都會發送到 kafka 的隊列中,等待訂閱者消費,所以每一個配置都將必不可少。

:kafka 消息 topic,領域區分(建議: )。

:kafka 集群地址(如:127.0.0.1:9091,127.0.0.1:9092)。

:kafka 事務 id 前綴,領域區分。

:使用業務的 dataSource。


在事件觸發前,需要實現 ,實現自定義的本地監聽分發。

交由 spring 託管

事件發布


對於領域內事件訂閱者

的 方法提供領域內訂閱者的事件分發,以便本地訂閱者可以訂閱到關注的事件消息。這些領域內的訂閱者,只需要在 中模式匹配進行分發。

對於跨領域事件訂閱者

依賴:針對其他領域服務及第三方系統,提供了一致的 api。

註解掃描支持配置

訂閱事件消息:同一個領域的事件在同一個消費者類中處理。

也需要在 spring 上下文中託管。

@KafkaConsumer

: kafka Consumer groupId,領域區分

: kafka 消息 topic

: 可自行配置的 kafka 地址,默認值為 。支持自定義修改,用戶只要負責把這些配置放到 env 或者 properties 里。如:

@KafkaListener

serializer 事件消息解碼器,由事件發送方提供。

通過以上已經知道在事件中,領域內的訂閱者和跨領域的事件訂閱者消費事件消息存在差異:

領域內的事件訂閱者,通常不能脫離領域的存在,存在領域內強關係的,但又需要解耦。

跨領域的事件消息訂閱,通常只需保證最終一致性,他們相對事件發送方沒有強依賴關係。

需要注意的是:在 eventbus 中,領域內消費事件之後還是會將事件消息廣播出去。因為不能保證不會有其他領域對發生的事件感興趣!

如商品領域的商品變價審核通過後,觸發了審核通過事件。事件觸發後將使價格生效,這部分生效操作可以通過領域內的事件訂閱進行解耦。因為更新了商品價格,可能存在庫存系統或者其他業務系統對商品數據敏感,可以通過跨領域事件發送-訂閱,做商品的數據推送。


Eventbus將訂閱者 api 進行了有趣的拓展,加入binlog-kafka動態緩存更新支持。使用方法與事件的訂閱者方法類似,唯一的不同是不再需要消息解碼器。@BinlogListener


總結

總體來說,不論是事件的發送還是訂閱,對於開發者而言都是易用的,並且沒有多餘的配置。對於第三方系統的支持也做的非常優秀,希望在日常開發中能夠更加靈活的運用,盡量減少不必要的耦合,並能經受實踐考驗!

有關eventBus的具體實現細節,將由小夥伴 hz.lei 來進行剖析!

下期預告:hz.lei:DDD-事件匯流排實現架構原理分析

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 TodayTech 的精彩文章:

TAG:TodayTech |