Event Sourcing 是什麼?他和 CRUD 的差別在哪裡?

古古

2025/01/14


Event Sourcing 的設計理念可以說是和一般常見的 CRUD 完全不同,我一開始聽到的時候也驚嘆「啊??竟然還能這樣??」,所以這篇文章我們就來了解一下,到底什麼是 Event Sourcing 吧!

什麼是 Event Sourcing? #

所謂的 Event Sourcing,中文硬翻的話是「事件溯源」,重點在於「事件」這兩個字。

而 Event Sourcing 的概念,其實就只是 「將每一筆發生的 Event(事件)都記錄下來」 而已,比想像中單純!

舉例來說,如果大家去銀行存款/提款的話,銀行一定會記錄「你在某某時間存了多少錢」,因此當你後續去畫簿子(或是查看交易記錄時),就可以看到自己「每一筆存款/提款的時間、以及金額的大小」,而這種「把每一個 Event 都記錄下來」的設計方式,就稱為是 Event Sourcing。

也因為在 Event Sourcing 中,我們所儲存的是「每一個 Event 的記錄」,而不是儲存「最終的餘額結果」,所以假設使用者想要知道他現在到底有多少存款的話,那我們就只能手動的一筆一筆 event 加總,也就是「把事件全部重頭執行一遍」,最終就可以得到他的最終餘額。

所以像是在上面的例子中,我們就需要加總這 3 筆 event,也就是「存款 500」、「存款 1000」、「提款 200」,因此使用者最終的餘額就是 500 + 1000 - 200 = 1300

因此 Event Sourcing 說穿了,就只是將 「每一筆發生的 Event 忠實的記錄下來」 的架構模式而已!

Event Sourcing 和傳統 CRUD 的差別在哪裡? #

大概了解了 Event Sourcing 的概念之後,我們也可以來比較一下 Event Sourcing 和傳統 CRUD 的差別在哪裡。

由於 Event Sourcing 的特徵是「將每一個發生的 Event 都記錄下來」,因此在資料庫中我們所儲存的,是每一個 Event 發生的時間。優點是可以知道每一個 Event 的具體發生的時間,缺點則是沒辦法馬上知道最終的總額是多少,需要一筆一筆將 Event 全部加總之後,才能夠得到結果。

而傳統 CRUD 則不一樣,傳統的 CRUD 是「直接將最終的結果儲存下來」,因此當使用者存錢時,CRUD 就是直接去修改使用者的當前餘額,將他修改成最終的數字。因此 CRUD 的優點是可以快速地知道當前餘額是多少,但是缺點是不知道使用者中間到底交易過幾次。

也由於 Event Sourcing 和 CRUD 在本質上的不同,因此一般來說,通常是「對每一個 Event 都要詳細記錄的情境」才需要使用 Event Sourcing 來設計,像是金融業銀行、股票買賣、Audit Log…等等,這種要細到每筆帳都要清算的情況,就很適合用 Event Sourcing 來實作。

而如果沒有這種需求的話,其實用 CRUD 就真的很夠用了,因為一般來說大家在意的不是那個過程,而是最終的結果,所以這也是為什麼 CRUD 目前還是後端設計主流,就是因為 CRUD 可以應付大部分的真實場景。

所以作為一個後端工程師,能夠熟練掌握最基本的 CRUD 能力還是非常重要的,基本功不能丟啊!

Event Sourcing 的優化 #

呈上面所說,因為 Event Sourcing 就是瘋狂的把每一筆發生過的 Event 給記錄下來,所以每次要得到最終結果的時候,都得要重新一筆一筆的把 Event 給加總,才能夠得到最終結果,但其實在實作上,是有一些手段可以加速的。

像是我們可以在每天加總該天的 Event,最後生成一個當天的最終結果給使用者看,所以像是股票買賣記錄,就可以在當天晚上結算,先得到一個結果(術語稱為 snapshot),這樣後續就不用再重頭一筆一筆加總 Event 了,只要從今天的結果繼續往下加總明天的 Event 就好。

Event Sourcing 的優勢 #

補充:本段內容擷取自 高速大量業務的應用架構關鍵

另外 Event Sourcing 也有一個超級強大的優勢,就是能夠 「提高後端系統的吞吐量」。

因為 Event Sourcing 是瘋狂把每一筆 Event 記錄下來就好,所以他就不需要執行 SELECT SQL 語法,先查到要更新的是哪一筆數據,再進行更新,Event Sourcing 就只要直接無腦把 Event 數據 INSERT 到資料庫就好,因此資料庫就可以特意挑選那種擅長寫入的資料庫了!

Event Sourcing 總結 #

所以總結上面的介紹,所謂的 Event Sourcing,就是 「將每一筆發生的 Event 都記錄下來」,因此將來不管是要查詢使用者的哪一筆操作有問題、還是要回溯到當下的狀況,都可以用我們所儲存的 Event 數據來回溯。

而 Event Sourcing 和 CRUD 最大的差別,就在於:

  • Event Sourcing 是「儲存每一筆 Event」。
  • CRUD 是「儲存數據的最終結果」。

因此大家就可以根據自己的情境,選擇最適合你的架構了~

補充:Event Sourcing 和 DDD #

其實只要講到 Event Sourcing,就一定會提到跟他很有關係的 DDD。

所謂的 DDD,全稱是 Domain-Driven Design(領域驅動設計),概念大概是將程式劃分成好幾個領域,每一個領域需要搭配一個領域專家,並且會有一個聚合根(Aggregate),負責該領域的所有事件和數據處理。

上面這段文字看起來很難對不對?嗯其實我也覺得很難😂,感覺文字分開看我都懂,合在一起看就不太懂🥹。

由於 DDD 我也只有略懂而已,所以大家如果有興趣的話,也可以再上網查詢「CQRS、Aggregate」…等關鍵字,這邊就不班門弄斧了🙏。

補充 2:Event-Driven Design 是什麼? #

其實了解了 Event Sourcing 的目的是「儲存每一筆 Event 的記錄」之後,要了解另一個名詞 Event-Driven Design 就很容易了~

所謂的 Event-Driven Design,中文翻譯為「事件驅動設計」,概念大概就是 「當某事件發生時,我們要執行什麼功能」。

舉例來說,假設我們架設了一組 RabbitMQ,你就可以說「當某個 Queue 出現 message 時,我們就要更新資料庫」,而這其實就是一個 Event-Driven Design,也就是「當某個事件出現時,我們就執行什麼程式」這樣。

另外如果大家有寫過前端的程式的話,其實整個前端的架構都是 Event-Driven Design,像是「當使用者點擊某個 Button,我就要執行某段程式」,或是「當使用者滑動視窗時,我要改變 Dom 的狀態」…等等,整個前端其實就是超級大的 Event-Driven Design 架構。

也因為 Event-Driven Design 的使用情境很廣泛(不僅前端廣泛使用,後端其實也會用到),所以建議大家要了解一下他的概念會比較好~。

結語 #

這篇文章我們介紹了 Event Sourcing 是什麼,並且也比較了 Event Sourcing 和傳統 CRUD 的差別,最後也補充了一下 DDD 和 Event-Driven Design 的概念,希望可以幫助大家了解 「Event(事件)」 到底是在玩什麼花樣。

如果你對後端技術有興趣的話,也歡迎免費訂閱 《古古的後端筆記》電子報 ,每週二為你送上一篇後端技術分享,那我們就下一篇文章見啦!

免費訂閱《古古的後端筆記》電子報

每週二學習後端技術,和 2700 人一起變強💪