事件驅動“Event-Driven”是什麼意思?

banq發表於2017-02-08
Martin Fowler對事件驅動 EventSourcing和CQRS最近進行了權威解釋:

去年年底,我與ThoughtWorks的同事們一起參加了一個研討會,討論“事件驅動”應用程式的性質。 在過去的幾年裡,我們透過使用大量的事件建立了許多系統,常被稱讚,也常詛咒。我們的北美辦公室組織了一次峰會,來自世界各地的ThoughtWorks高階開發人員分享了想法。

峰會的最大結果是認識到當人們談論“事件”時,他們實際上意味著一些完全不同的事情。 所以我們花了很多時間試圖從中挑出一些有用的模式。 本文就是我們確定的主要內容的簡要總結。

事件通知

當系統傳送事件訊息以通知其他系統在其領域中進行更改時,會發生事件通知這種情況。事件通知的一個關鍵元素是源系統並不真正關心它發出事件的響應。通常它不會期望它發出事件的任何回應,或者如果就是有一個響應需要源系統的關注,這種關注也是間接的。在傳送事件的邏輯流和響應對該事件的某些響應的任何邏輯流這兩者之間將存在明顯的分離。

事件通知很好,因為它意味著低階別的耦合,並且設定非常簡單。然而,如果真的有一個邏輯流執行在各種事件通知,它可能會成為問題。問題是,很難看到這樣的流程,因為它不會在任何程式文字中顯式突出。 通常,找出此流程的唯一方法是監視實時系統。 這可能讓這種流變得難以除錯和修改。 危險是,很容易做出與事件通知解耦很好的系統,但是卻沒有意識到潛在地存在你看不見的大規模流量,這樣在未來幾年將自己置於麻煩之中。 該模式(事件通知)仍然非常有用,但你必須小心的陷阱。

這個陷阱的一個簡單示例是當事件用作passive-aggressive命令時:源系統期望接收者執行動作時,並且應該使用命令command訊息(不是事件訊息)來顯示該意圖(表示意圖應該是命令,而不是事件,事件包含的是已經執行意圖進行修改後的資料 banq注),但是卻將訊息風格不恰當變為事件。

事件不需要攜帶很多資料,通常只是一些id資訊和連結指向傳送者,可以查詢更多的資訊。 接收者知道某事已經改變,可以獲得關於改變的性質的一些最小資訊,然後可向傳送者發出請求以決定下一步做什麼。

事件承載狀態轉移

當您想以不需要聯絡源系統就可以進行下一步工作的方式來更新系統的客戶端時,將使用該模式。 每當客戶端更改其詳細資訊(例如地址)時,客戶管理系統可能會觸發事件,其中事件包含已更改的資料的詳細資訊。 然後,接收者可以利用這種變化的事件通知來更新其自己的客戶資料副本,使得它以後再也不需要與主客戶系統進行通訊就能完成它自己的工作。

這種模式的一個明顯的缺點是,有很多資料被丟擲和並存在大量的複製副本。但是,在空間充足的儲存時代,這不是一個問題。我們獲得的是更大的恢復力,因為如果客戶系統變得不可用,接收系統還是可以執行。 我們減少了延遲,因為沒有遠端呼叫RPC以同步方式訪問客戶資訊。我們不必擔心客戶系統上的負載是否滿足來自所有客戶系統的查詢。 但它涉及更復雜的接收器,因為它必須整理出保持原來順序的所有的狀態,它通常在需要時更容易呼叫傳送者以獲得更多的資訊。

事件源Event-Sourcing

事件源的核心思想是,每當我們改變系統的狀態時,我們將狀態變化記錄為一個事件,我們可以透過在將來的任何時間重新處理事件來自信地重建系統狀態。事件儲存器成為真實業務變動的主要來源,並且系統狀態是純粹從事件匯出的。 對於程式設計師,最好的例子是版本控制系統。所有提交的日誌是事件儲存,源樹的工作副本是系統狀態。

事件溯源引入了很多問題,我不打算在這裡說太多,但我想強調一些常見的誤解,事件處理不是一定需要非同步,考慮更新本地git儲存庫的情況 -這完全是一個同步操作,因為它如subversion一樣更新一個集中版本控制系統。 當然還有很多這樣的提交commit能夠實現各種有趣的行為,git是一個很好的例子,但核心提交從根本上是一個簡單的動作。

另一個常見的錯誤是假設任何使用事件源系統的人都應該理解並訪問事件日誌以確定有用的資料。 但是事件日誌的知識卻相當有限。 我在一個編輯器中編寫它,這個編輯器不知道原始碼樹中的所有提交,它只是假定磁碟上有一個檔案。 事件源系統中的大多數處理應基於有用的工作副本。 只有一個元件應該知道如何從事件儲存區匯出該工作副本。我們可以有不同資料結構的多個工作副本,當然如果這樣做有幫助的話; 但通常應該在領域處理和從事件日誌匯出工作副本之間有明確的區分。 使用事件日誌時,構建工作副本的快照通常是有用的,這樣您就不必在每次需要工作副本時都從頭開始處理所有事件。

事件源具有許多有趣的優點,當考慮版本控制系統的價值時很容易想到。事件日誌提供強大的審計功能(會計憑證來往事務是科目帳戶餘額的事件源. banq注)。 我們可以透過重放事件日誌來重建歷史狀態。 我們可以透過在重放時注入假設事件來探索替代歷史。事件源使得具有非永續性工作副本(例如記憶體映像)是合理的。

事件源確實有其問題。 當結果取決於與外部系統的互動時,回放事件變得有問題。我們必須弄清楚如何隨時間的變化處理事件的模式。 很多人發現事件處理給應用程式增加了很多複雜性(儘管我不知道這是否是由於派生工作副本的元件和執行域處理的元件之間的分離得比較差導致的)。

CQRS

命令查詢響應分離(CQRS )是具有用於讀取和寫入資訊的單獨資料結構的概念。嚴格地說,CQRS不是真的關於事件,因為你可以使用CQRS,而在你的設計中不存在任何事件。但通常人們將CQRS與早期模式組合在一起,因此他們在峰會就有存在的必要進行演講。

CQRS的理由是,在複雜領域中,處理讀取和寫入的單個模型太複雜,我們可以透過分離模型來簡化, 這在訪問模式有所不同時尤其有吸引力,例如大量讀取和很少的寫入。但是使用CQRS的收益必須與具有單獨模型的額外複雜性相平衡。 我發現很多同事對使用CQRS非常警惕,發現它經常被濫用。

瞭解這些模式

作為一個軟體植物學家(botanist),渴望收集樣品,我發現這是一個棘手的情況。核心問題是混淆不同的模式。在一個專案中,有能力和經驗豐富的專案經理告訴我,事件源是一個災難 - 任何更改花了兩倍的工作來更新讀和寫模型。就在這篇短文中,我可以檢測到事件源和CQRS之間的潛在混淆 - 那麼我怎麼弄清楚哪個是罪魁禍首呢?專案的技術主管聲稱主要的問題是許多非同步通訊,當然這是已知的複雜性 - 源頭,但非同步機制不是事件源或CQRS的必要部分。此外,我們必須注意,所有這些模式在正確的地方是好的,當放在錯誤的場景下就是壞的。但是,當我們將模式混合在一起時,很難弄清楚什麼是正確的場景。

我想寫一些確定的論文,把所有這些困惑排除在外,並給出瞭如何做好每個模式,以及什麼時候應該使用的堅實指導。 可悲的是我沒有時間去做。我寫這個筆記,希望它將是有用的,但我很清楚,它遠遠落後於真正需要的。

What do you mean by “Event-Driven”?

相關文章