事件驅動架構是一種促進生產的軟體架構正規化。事件驅動架構在用微服務構建的現代應用中非常普遍,它用事件來觸發、解耦服務之間的通訊。事件可以是狀態的變更,比如將商品放入購物車;也可以是某種標識,比如訂單的發貨通知。
在傳統的軟體架構中,應用邏輯是通過請求、過程驅動的。一個請求執行一段邏輯同步返回一個響應,在業務邏輯中,將要執行的程式碼按照過程順序進行編排。而事件驅動架構中,事件消費者會以非同步的方式處理事件生產者產生的事件,原來過程當中的邏輯交給事件消費者去處理,解開服務之間的耦合,使應用的邏輯聚焦,應用的職責單一,程式碼更加簡潔,也能提升系統的響應能力。
在 2020 年,本文作者開源了 Go 語言的分散式事務框架 Seata-Golang。Seata-Golang 實現 AT 模式和 TCC 模式,這兩種模式都是過程驅動。到了 2022 年,隨著對雲原生技術的理解深入,從 Kubernetes Control-Loop 思想中獲得靈感,全新設計了高效能、無侵入、事件驅動的 Go 語言分散式事務框架 hptx,以及支援跨語言分散式事務、讀寫分離、分庫分表的 Mesh 方案 DBPack。這兩款產品都能解決分散式事務問題,前者只支援 Go 語言,後者支援任意程式語言。他們採用了相同的事件驅動架構。下面進行詳細的說明。
在 Seata 的設計中,事務發起者發起全域性提交後,首先會判斷該事務是否允許非同步提交,如果允許,則直接返回提交成功,然後由 AsyncCommittingSessionManager
來非同步地通知每個分支事務提交,AT 事務預設允許非同步提交。如果不允許非同步提交,事務協調者會依次通知全域性事務參與者即每個分支事務提交,所有分支事務提交成功後,同步返回給事務發起者全域性事務提交的結果,如上圖。事務協調者通知事務參與者提交過程中發生了異常,會將該全域性事務標記為 CommitRetrying
狀態,將會有一個 RetryCommittingSessionManager
定時從持久儲存中撈取標記的全域性事務重試提交。
全域性回滾的過程與上圖類似,全域性回滾時,AT 模式和 TCC 模式都是同步執行,依次通知每個分支事務回滾,然後再響應回滾結果給事務發起者。如果回滾失敗,則將全域性事務標記為 RollbackRetrying
,由 RetryRollbackingSessionManager
定時撈取標記的全域性事務資料重試回滾。
Seata-Golang 的使用者經常會問一個問題,事務協調者 TC Server 怎麼做高可用?Seata 包括 Seata-Golang 預設推薦使用 Mysql 資料庫作為 TC 狀態資料的持久化儲存。TC Server 本身則是無狀態應用,可以部署多個副本,但這裡就存在一個問題:多個對等副本里的 AsyncCommittingSessionManager
、RetryCommittingSessionManager
、RetryRollbackingSessionManager
都會從資料庫去撈取對應的資料執行,會導致事務的提交、回滾重複執行,雖然 AT 模式天然做到冪等,TCC 模式由使用者保證冪等,但總是存在一定的資源浪費,且不夠優雅。
上圖展示了 hptx 和 dbpack 的事務協調邏輯,事務發起者 AggregationSvc 發起全域性事務提交、回滾,僅僅是修改 ETCD 中的資料狀態,然後立即返回。訂單服務和商品服務使用字首 bs/${appid}
Watch 儲存在 ETCD 中的分支事務資料,當分支事務的資料發生過變更後,ETCD 馬上推播一個變更事件給相應服務,訂單服務和商品服務收到變更事件後,將資料加入 workqueue
去執行提交或回滾的邏輯。AggregationSvc 提交、回滾時不會呼叫 OrderSvc、ProductSvc 的介面,整個過程通過 ETCD 解耦後非同步執行。
事務分支提交或者回滾失敗後,會重新進入到 workqueue
當中繼續消費,直至提交、回滾成功,或回滾超時(AT 模式回滾操作涉及到全域性鎖的釋放,需要設定超時時間,即 retry_dead_threshold
)。
在這個架構中,已經沒有中心化事務協調者 TC Server,使用者只需要關心自身應用的高可用,如果應用多副本部署,hptx 和 dbpack 會通過 etcd 選主,只有選為 master 的副本才能 watch 自身產生的分支事務資料去做提交、回滾,避免了提交、回滾邏輯重複執行的問題。整合 hptx,只需要依賴相應的 sdk,而不需要部署額外的 TC Server,但狀態資料的儲存由原來的 Mysql 換成了 ETCD。
全新的、雲原生的、事件驅動架構,更加簡潔,效能更強。採用 hptx 的應用事務協調效能比 Seata-Golang 提升 1 倍,通過 dbpack 以 mesh 方式協調分散式事務效能比 seata-golang 提升了百分之 50。下面是一些測試資料:
環境 | 效能 | |
---|---|---|
seata-golang | 2018 款 Mac book pro | 每秒 18.54 筆事務 |
hptx | 2018 款 Mac book pro | 每秒 38.89 筆事務 |
dbpack | 2018 款 Mac book pro | 每秒 28.09 筆事務 |
hptx | 阿里雲 ecs ecs.sn1ne.xlarge (4 核 8G) | 每秒 35.15 筆事務 |
hptx 是當前效能最強的雲原生、無侵入分散式事務解決方案,選擇其他記憶體型儲存元件理論上可以得到更高的效能,但綜合可靠性和效能,ETCD 是目前最好的選擇。
經過持續地在分散式事務領域的研究總結,使分散式事務框架不斷進化,從最初的相容 java seata 的 seata-golang v1 版本,到雲原生的、無侵入的、基於 grpc 的 seata-golang v2 版本,到基於 ETCD watch 機制的、事件驅動的 hptx,再到跨語言的 dbpack,分散式事務一直在進化,能力也在進一步增強。
歡迎感興趣的同學加入我們社群一起交流討論分散式事務問題、DBMesh 問題,進群或參與社群建設請新增微信:scottlewis。
Hptx 專案地址:https://github.com/cectc/hptx
Hptx samples:https://github.com/cectc/hptx-samples
DBPack 專案地址:https://github.com/cectc/dbpack
DBPack 檔案:https://cectc.github.io/dbpack-doc/
DBPack-samples:https://github.com/cectc/dbpack-samples