July 04 18:38~19:46
▲圖1:EventStoreDB的使用者自訂投影程式
前言
上一集介紹ezKanbana如何實作Projector以便在PostgreSQL資料庫中產生Read Model所需的資料,這一集回頭使用EventStoreDB的客製化Projection功能,建立另一種形式的Read Model。
***
透過JavaScript程式產生事件投影
Teddy在<讀取事件溯源(6):透過Projection查詢Event Store>介紹過EventStoreDB三種內建的Projection:$all、$ce-以及$et-。除了內建的Projection以外,EventStoreDB也支援使用者撰寫JavaScript程式來產生Projection。什麼,JavaScript程式?!沒錯,Teddy沒寫錯,鄉民們也沒看錯,就是JavaScript程式。EventStoreDB可以執行JavaScript程式,投影出使用者想要的event stream,再利用這個event stream產生讀取資料。
依據EventStoreDB官方文件的講法,它是一個為了寫入所開發的事件溯源資料庫,也是一個可以做為讀取模型的資料庫。EventStoreDB就是透過自訂Projection使得它可以做為取模型的資料庫。
圖1為ezKanban用來投影所有Board事件的JavaScript程式,第1行~第5行的fromStreams函數表示將這些event stream當成輸入來源。第11行~第13行則把所有接受到的事件,投影到另一個ReplayEvents-By-Board-[board id]的event stream裡面。這個使用者自行定義的event stream,可以做為ezKanban的replay功能的讀取模型。也可以拿這個event stream當成資料來源,傳給上一集<事件溯源(10):實作Projector>裡面的NotifyBoardContent程式,讓它即時投影出GetBoardContent所需的讀取模型。
***
採用EventStoreDB當成讀取資料庫的架構如圖2所示,以GetBoardContent查詢為例,它會直接從ReplayEvents-By-Board-[board id] event stream裡面讀出屬於某一個Board的所有事件,然後再呼叫NotifyBoardContent讓它即時重播這些事件並投影出目前狀態。
▲圖2:將EventStoreDB當成Read Database
ezKanban的GetBoardContent查詢並沒有使用這種方式當作讀取資料來源,但是團隊有用測試案例來驗證這種作法的效率,如圖3所示。
▲圖3:使用測試案例模擬將EventStoreDB做為GetBoardContent的讀取模型資料庫
***
效能比較
ezKanban團隊成員杜奕萱在她的碩士論文《套用命令與查詢責任分離以簡化聚合依賴:以 ezKanban 為例》比較使用PostgreSQL資料庫以及在上一集<事件溯源(10):實作Projector>產生JSON讀取模型的效能比較,如圖4所示。可以看出來,當卡片數量越多,套用CQRS的效益越大。
▲圖4:杜奕萱碩士論文所做的ezKanban在套用CQRS前後,GetBoardContent查詢的效能比較
在杜奕萱的碩士論文中並沒有比較這一集所介紹的採用EventStoreDB建立GetBoardContent讀取模型的方法,但ezKanban團隊在前幾天以圖3測試案例的形式做了非正式的比較,其結果如下:
- 在8000張卡片的情況之下,花費的時間大約2179 ms。這個速度還是比沒有建立讀取資料要來得快很多(原本需要16841 ms)。
- 團隊進一步模擬以1000筆領域事件建一次Snapshot為例,則產生GetBoardContent的時間可以縮短成87ms,非常接近在PostgreSQL資料庫中用JSON格式產生讀取模型的73ms時間。
***
EventStoreDB自訂投影的好處
若採用上一集<事件溯源(10):實作Projector>所介紹的架構來套用CQRS,則讀取端的Projector需要具備idempotent的特性,而且若讀取資料庫損毀,也需要想辦法讀取原本的領域事件再次投影出讀取模型(replay)。使用EventStoreDB的自訂投影,只要撰寫好JavaScript程式,EventStoreDB會負責產生投影,使用者不用煩惱idempotent的問題。至於replay也很簡單,因為所有的領域事件都保存在EventStoreDB所投影出的stream裡面,所以只要重頭讀取一次該stream的所有事件再逐一apply即可。雖然這種方式的效能沒有直接用JSON儲存View Model來得快,但如果有需要只要加上Snapshot,便可以大幅改善EventStoreDB做為讀取資料庫的效能。
至於CQRS的讀取資料庫要採用哪種方式,就要看鄉民們各自專案需求與技術能力而定。
***
下集預告
Event Sourcing與CQRS的核心觀念與技術介紹的差不多了,下一集之後談幾個比較進階一點的議題,先從幫Aggregate或是Read Model建立Snapshot(快照)談起。
***
友藏內心獨白:Write DB也可以是Read DB。
沒有留言:
張貼留言