基于MySQL和DynamoDB的强一致性分布式事务实践
點擊上方“朱小廝的博客”,選擇“設為星標”
后臺回復"書",獲取
后臺回復“k8s”,可領取k8s資料
在單體應用向微服務架構轉型的過程中,本地事務已不再滿足系統一致性需求,為了解決這一問題,前人在對性能和數據一致性反復權衡的過程中總結了許多典型的協議和算法,各有優劣。本文我們將深入探討 Freewheel 如何實現無單點故障的可擴展分布式事務實現模型。
1為什么需要分布式事務?
當應用程序有嚴格的數據一致性要求時,ACID 事務是必須的,如果一個事務涉及的所有操作能夠放在一個服務內部,且共用一個數據庫,那么只用在一個方法里同一個事務下操作數據庫即可。然而為了提升系統整體的可靠性,方便各個模塊獨立演化,系統從單體應用演進為微服務架構。隨著數據體量的增長,數據源也從 MySQL 擴展到關系型數據庫 Amazon Aurora 和 NoSQL 數據庫 (Amazon DynamoDB),基于多樣化索引和查詢數據的需求,引入了搜素引擎 (ApacheSolr 和 ElasticSearch ) ,多服務交互、多數據源并存產生了分布式事務。
Freewheel 分布式事務應用場景有三個:
多服務,同數據源: 業務單元跨越多個獨立服務,服務訪問同一個數據源,如 MySQL。
單服務,不同數據源: 業務單元涉及一個獨立服務,但這個服務訪問多個數據源,如 MySQL,DynamoDB。
多服務,不同數據源: 業務單元跨越多個獨立服務,每個服務訪問不同數據源,如 MySQL,DynamoDB。
綜合考慮 Freewheel 的業務需求后,我們實現了多引擎數據庫分布式事務。
2多引擎數據庫分布式事務設計
Freewheel 分布式事務方案主要設計目標如下:
數據強一致性: 確保該事務范圍內的所有操作都可以全部成功或者全部失敗,事務具有原子性、一致性、隔離性、持久性 4 個特性。
Atomicity(原子性):一個事務中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
Consistency(一致性):在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。完整性包括外鍵約束、應用定義等約束不會被破壞。
Isolation(隔離性):數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
Durability(持久性):事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
系統高可用: 遵循“design for failure”的設計原則,硬件層面,采用服務節點多 region 多 AZ 部署和節點故障快速自恢復的策略來保證系統的高可用。軟件層面,設計 failover 機制應對服務異常。
可擴展: 應用 Auto Scaling 服務,它會基于設定的負載壓力,自動進行擴展和縮容,來保證服務正常運行。
易用性: 分布式事務應用 API:易學,易懂,易記,系統設計上無業務侵入,沒有額外的編碼或測試工作。
3多引擎數據庫分布式事務技術選型
常見分布式事務解決方案對照表:
結合 Freewheel 強一致性業務需求,多數據源分布式事務將由 XA、2PC 和 Seata 這些解決方案組合而成。
Seata 框架設計思想
基于 XA 的 Aurora 分支事務
基于 2PC 的 DynamoDB 分支事務
4多數據源分布式事務解決方案
架構解析
Freewheel 分布式事務依托在 Freewheel 數據訪問層中間件 (DAL) 上,這個中間件是由 Freewheel 平臺團隊自主研發的,它的目標是為上游應用提供更好的數據訪問,為下游數據源提供更好的保護。為了方便描述,下文均用 DAL 來作為 Freewheel 數據訪問層中間件的簡稱。
分布式事務由這三個組件來協商處理:
Transaction Coordinator (TC):?事務協調器,維護全局事務的運行狀態,負責協調并驅動全局事務的提交或回滾。
Transaction Manager (TM):?控制全局事務的邊界,負責開啟一個全局事務,并最終發起全局提交或全局回滾的決議。
Resource Manager (RM):?控制分支事務,負責分支注冊、并接收事務協調器的指令,驅動分支(本地)事務的提交和回滾。
為了預防死鎖,并且減少 DAL RM 和 TC 之間的 交互,降低對 TC 的依賴,同一個分布式事務操作放在同一個 DAL 節點,由此,DAL RM 可以方便的在單節點控制和協調分支事務,完成全局事務的提交和回滾。
以多服務,不同數據源 (Aurora 與 DynamoDB) 為例,描述 Freewheel 分布式事務過程。
A Service TM 向 TC 申請開啟一個全局事務,全局事務創建成功并生成一個全局唯一的 XID。
XID 在微服務調用鏈路的上下文中傳播。
TM 向 TC 發起針對 XID 的全局提交或回滾決議。
TC 向 DAL RM 發起全局提交或回滾決議。
DAL RM 對 XID 下管轄的全部分支事務完成提交或回滾請求。
數據訪問層資源管理器 (DAL RM) 實現
基于業務需求,DAL 分布式事務支持的數據源為 MySQL 和 AWS DynamoDB,下面章節闡述了這兩個數據源 ACID 技術實現。
分布式事務設計中新建了事務控制表、事務記錄表、索引表及業務鏡像表:
事務控制表:記錄事務運行狀態開始、提交、回滾。
事務記錄表:存儲正在發生事務信息。
索引表:記錄記錄主鍵 ID, 用于實現排它性對其他事務更新與普通更新。
業務鏡像表:存儲業務原值。
?Aurora/MySQL
采用 MySQL XA 2PC 來保證 ACID,原因如下:
Mysql 5.7 版本已經支持 XA,目前 Aurora 也是 Mysql 5.7.x。
XA 強一致性。
不侵入業務,這會減少業務方的工作量。
這個時序圖描述了 RM 對 MySQL 事務的工作流程:
一個事務操作,由同一個 DAL RM 處理,相同 DB 下業務事務處理,放在一個 XA 操作里:
節省 XA 連接 fd。
減少 DAL RM 和 Aurora 之間的 XA 交互次數。
避免多個 XA 分支事務上的數據操作沖突。
SQL CRUD 語句應該使用觸發行鎖的索引操作,否則會觸發表鎖,影響系統吞吐量。
?AWS DynamoDB
DynamoDB 提供了本地事務接口 TransactGetItems 和 TransactWriteItems, 它等效于 MySQL 批量操作,對于相互間有上下文或者依賴的操作并不可用,這限制了它在應用中的使用場景,詳細信息請參考 TransactGetItems 和 TransactWriteItems。
DynamoDB 本身沒有分布式事務機制,DAL 結合 DynamoDB 功能屬性,對提供的插入、更新、刪除和查詢接口,設計 2PC 機制 來滿足 DynamoDB 的 事務屬性。
下表顯示了分布式事務操作 (DisTxDAL) 和其他操作之間的隔離級別。
更新接口實現方法
一階段
應用本地事務原子地備份事務記錄及備份索引
應用本地事務原子地更新附加事務信息業務值及備份業務原值到鏡像表
二階段
如果決議是提交,應用本地事務原子地移除業務記錄事務屬性、刪除鏡像記錄、刪除備份事務記錄
如果決議是回滾,應用本地事務原子地恢復業務記錄、刪除鏡像記錄、刪除備份事務記錄
插入接口實現方法
一階段
應用本地事務原子地備份事務記錄及備份索引
插入帶有事務屬性信息的業務記錄
二階段
如果決議是提交,應用本地事務原子地移除業務事務屬性、刪除備份記錄
如果決議是回滾,應用本地事務原子地刪除業務記錄、刪除備份記錄
刪除接口實現方法
一階段
應用本地事務原子地備份事物記錄及備份索引
更新帶有事務屬性信息的業務記錄, 標注為刪除操作
二階段
如果決議是提交,應用本地事務原子地刪除事務記錄、刪除業務記錄
如果決議是回滾,應用本地事務原子地恢復業務記錄、刪除備份記錄
查詢接口實現方法
事務進行中的數據含有事務屬性信息,xid 表示事務全局事務 ID, operation 表示事務操作接口 create、update、delete,這里 item 表示業務數據元素。
基于業務數據變更表及寫接口實現方法,實現了在讀提交與讀未提及查詢方法:
判斷記錄是否含有事務屬性,如果無,返回記錄,否則到步驟 2
判讀隔離級別,如果讀提交,步驟 3,如果讀未提交,步驟 5
記錄事務操作是 create, 返回空,否則如果是 delete,去除事物屬性信息,然后返回,否則步驟 4
本地事務原子地讀取鏡像表與業務表,如果鏡像表值存在,返回,否則返回業務表值,都不存在返回空
如果記錄事務操作是 delete,返回空,否則返回記錄
數據訪問層事務管理器 (DAL TM) 實現
為了方便用戶使用,分布式事務 API 里封裝了與事務協調器及 DAL 資源管理器的交互過程,交互過程對應用是透明的,下面是分布式事務 API:
type DistributedTransApi interface {DisTxDAL(ctx context.Context, fn TranFunc) error } type TranFunc func(ctx context.Context) error微服務之間,微服務與數據庫訪問層之間采用 google rpc 調用,服務之間關鍵數據都是基于 context metadata,如果經過兩層服務交互, 就會導致 context metadata 丟失。舉例來說,A 服務調用 B 服務,B 服務調用 C 服務,那么 C 服務就會缺失 A 服務 context metadata,針對這種情況,DAL 提供了通用函數用于提取 DAL 相關的元數據,供應用方按需添加。
func ExtractDalMetadata(ctx context.Context) (metadata.MD, error)數據訪問層事務協調器 (DAL TC) 實現?
協調器主要功能點:
分配事務 XID,維護全局事務的運行狀態,負責協調和驅動全局事務的提交或回滾;
故障轉移:提交 / 回滾。
?分配事務 XID
全局分配唯一事務 ID,供 DAL TM 獲取,此數據需要在同一事務的業務服務間傳輸共享。
?事務協調
維護全局事務的運行狀態,負責協調和驅動全局事務的提交或回滾。
?故障轉移
DAL TC 是 HA 多節點實例,引入 ETCD leader 選舉機制來保證只有一個 TC 實例承擔 failover 功能,詳細信息在系統高可用章節軟件層面 failover。
系統高可用
?硬件層面
為了預防硬件故障對高可用的影響,DAL,TC 和 ETCD 服務均是多 Region 多 AZ 部署,并且基于服務的特性配置了相應的服務策略:
ETCD 采用自恢復策略
DAL 和 TC 服務采用了彈性伸縮策略
美東美西均部署相應服務作為服務災備策略,下圖是美東地區的解釋圖(美西類似)。
?軟件層面 Failover
在 DAL 應用或者業務應用遇到異常退出時,軟件層面 Failover 機制是為了能不發生死鎖,并且繼續處理未完成分布式事務,實現方法如下:
DAL TM 接口添加超時控制,由應用設置事務的超時時間,默認是 60 秒
DAL RM 在事物開始、提交或者回滾階段存儲 xid 信息,如過期時間,運行狀態等,在業務接口調用里存儲業務處理記錄
DAL TC 輪詢地從事務控制表里獲取超時事務。基于事務狀態處理:如果 start or rollback:觸發 Rollback,如果 commit:觸發 commit
5未來展望
Freewheel 強一致性分布式事務未來會支撐更多的數據源,如 Redis、Solr 和 ElasticSearch 等,目前的數據庫訪問層 API 是基于 gRPC,這對數據庫訪問層使用方帶來了一定技術語言限制,未來會探究 GraphQL 在數據庫訪問層分布式事務應用的可行性。
想知道更多?掃描下面的二維碼關注我后臺回復"技術",加入技術群 后臺回復“k8s”,可領取k8s資料【精彩推薦】ClickHouse到底是什么?為什么如此牛逼!
原來ElasticSearch還可以這么理解
面試官:InnoDB中一棵B+樹可以存放多少行數據?
架構之道:分離業務邏輯和技術細節
星巴克不使用兩階段提交
面試官:Redis新版本開始引入多線程,談談你的看法?
喜馬拉雅自研網關架構演進過程
收藏:存儲知識全面總結
微博千萬級規模高性能高并發的網絡架構設計
總結
以上是生活随笔為你收集整理的基于MySQL和DynamoDB的强一致性分布式事务实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搞定 Go 语言,不会这些可不行
- 下一篇: 代码量减少90%,Java程序员必会的工