分布式事务在Sharding-Sphere中的实现
分布式事務的使用場景
01
ACID
一切從ACID開始說起。ACID是本地事務所具有的四大特征:
-
Atomicity:原子性
事務作為整體來執行,要么全部執行,要么全不執行。
-
Consistency:一致性
事務應確保數據從一個一致的狀態轉變為另一個一致的狀態。
-
Isolation:隔離性
多個事務并發執行時,一個事務的執行不應影響其他事務的執行。
-
Durability:持久性
已提交的事務修改數據會被持久保持。
關系型數據庫的本地事務完美的提供了對ACID的原生支持。但在分布式的場景下,它卻成為系統性能的桎梏。如何讓數據庫在分布式場景下滿足ACID的特性或找尋相應的替代方案,是本文將要闡述的話題。
02
CAP和Base理論
對于互聯網應用而言,隨著訪問量和數據量的激增,傳統的單體架構模式將無法滿足業務的高速發展。這時,開發者需要把單體應用拆分為多個獨立的小應用,把單個數據庫按照分片規則拆分為多個庫和多個表。
數據拆分后,如何在多個數據庫節點間保證本地事務的ACID特性則成為一個技術難題,并且由此而衍生出了CAP和BASE經典理論。
CAP理論指出,對于分布式的應用而言,不可能同時滿足C(一致性),A(可用性),P(分區容錯性),由于網絡分區是分布式應用的基本要素,因此開發者需要在C和A上做出平衡。
由于C和A互斥性,其權衡的結果就是BASE理論。
對于大部分的分布式應用而言,只要數據在規定的時間內達到最終一致性即可。我們可以把符合傳統的ACID叫做剛性事務,把滿足BASE理論的最終一致性事務叫做柔性事務。
一味的追求強一致性,并非最佳方案。對于分布式應用來說,剛柔并濟是更加合理的設計方案,即在本地服務中采用強一致事務,在跨系統調用中采用最終一致性。如何權衡系統的性能與一致性,是十分考驗架構師與開發者的設計功力的。
?
業界方法
具體到分布式事務的實現上,業界主要采用了XA協議的強一致規范以及柔性事務的最終一致規范。
01
XA
XA是X/Open CAE Specification (Distributed Transaction Processing)模型中定義的TM(Transaction Manager)與RM(Resource Manager)之間進行通信的接口。
Java中的javax.transaction.xa.XAResource定義了XA接口,它依賴數據庫廠商對jdbc-driver的具體實現。
mysql-connector-java-5.1.30的實現可參考:
com.mysql.jdbc.jdbc2.optional.MysqlXAConnection。
在XA規范中,數據庫充當RM角色,應用需要充當TM的角色,即生成全局的txId,調用XAResource接口,把多個本地事務協調為全局統一的分布式事務。?
一階段提交:弱XA
弱XA通過去掉XA的Prepare階段,以達到減少資源鎖定范圍而提升并發性能的效果。典型的實現為在一個業務線程中,遍歷所有的數據庫連接,依次做commit或者rollback。弱XA同本地事務相比,性能損耗低,但在事務提交的執行過程中,若出現網絡故障、數據庫宕機等預期之外的異常,將會造成數據不一致,且無法進行回滾。基于弱XA的事務無需額外的實現成本,因此Sharding-Sphere默認支持。
二階段提交:2PC
二階段提交是XA的標準實現。它將分布式事務的提交拆分為2個階段:prepare和commit/rollback。
開啟XA全局事務后,所有子事務會按照本地默認的隔離級別鎖定資源,并記錄undo和redo日志,然后由TM發起prepare投票,詢問所有的子事務是否可以進行提交:當所有子事務反饋的結果為“yes”時,TM再發起commit;若其中任何一個子事務反饋的結果為“no”,TM則發起rollback;如果在prepare階段的反饋結果為yes,而commit的過程中出現宕機等異常時,則在節點服務重啟后,可根據XA?recover再次進行commit補償,以保證數據的一致性。
2PC模型中,在prepare階段需要等待所有參與子事務的反饋,因此可能造成數據庫資源鎖定時間過長,不適合并發高以及子事務生命周長較長的業務場景。
Sharding-Sphere支持基于XA的強一致性事務解決方案,可以通過SPI注入不同的第三方組件作為事務管理器實現XA協議,如Atomikos和Narayana。
02
柔性事務
柔性事務是對XA協議的妥協和補償,它通過對強一致性要求的降低,已達到降低數據庫資源鎖定時間的效果。柔性事務的種類很多,可以通過各種不同的策略來權衡使用。
一階段提交 + 補償 :最大努力送達(BED)
最大努力送達,是針對于弱XA的一種補償策略。它采用事務表記錄所有的事務操作SQL,如果子事務提交成功,將會刪除事務日志;如果執行失敗,則會按照配置的重試次數,嘗試再次提交,即最大努力的進行提交,盡量保證數據的一致性,這里可以根據不同的業務場景,平衡C和A,采用同步重試或異步重試。
這種策略的優點是無鎖定資源時間,性能損耗小。缺點是嘗試多次提交失敗后,無法回滾,它僅適用于事務最終一定能夠成功的業務場景。因此BED是通過事務回滾功能上的妥協,來換取性能的提升。
TCC: Try-Confirm-Cancel
TCC模型是把鎖的粒度完全交給業務處理,它需要每個子事務業務都實現Try-Confirm/Cancel接口。
-
Try:
嘗試執行業務;
完成所有業務檢查(一致性);
預留必須業務資源(準隔離性);
-
Confirm:
確認執行業務;
真正執行業務,不作任何業務檢查;
只使用Try階段預留的業務資源;
Confirm操作滿足冪等性;
-
Cancel:
取消執行業務;
釋放Try階段預留的業務資源;
Cancel操作滿足冪等性。
這三個階段都會按本地事務的方式執行,不同于XA的prepare,TCC無需將XA的投票期間的所有資源掛起,因此極大的提高了吞吐量。
下面對TCC模式下,A賬戶往B賬戶匯款100元為例子,對業務的改造進行詳細的分析:
匯款服務和收款服務分別需要實現,Try-Confirm-Cancel接口,并在業務初始化階段將其注入到TCC事務管理器中。
匯款服務
-
Try:
檢查A賬戶有效性,即查看A賬戶的狀態是否為“轉帳中”或者“凍結”;
檢查A賬戶余額是否充足;
從A賬戶中扣減100元,并將狀態置為“轉賬中”;
預留扣減資源,將從A往B賬戶轉賬100元這個事件存入消息或者日志中;
-
Confirm:
不做任何操作;
-
Cancel:
A賬戶增加100元;
從日志或者消息中,釋放扣減資源。
收款服務
-
Try:
檢查B賬戶賬戶是否有效;
-
Confirm:
讀取日志或者消息,B賬戶增加100元;
從日志或者消息中,釋放扣減資源;
-
Cancel:
不做任何操作。
由此可以看出,TCC模型對業務的侵入強,改造的難度大。
消息驅動
消息一致性方案是通過消息中間件保證上下游應用數據操作的一致性。基本思路是將本地操作和發送消息放在一個事務中,下游應用向消息系統訂閱該消息,收到消息后執行相應操作。本質上是依靠消息的重試機制,達到最終一致性。消息驅動的缺點是:耦合度高,需要在業務系統中引入MQ,導致系統復雜度增加。
SAGA
Saga起源于1987年Hector & Kenneth發表的論文Sagas。
參考地址:
https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf
Saga工作原理
Saga模型把一個分布式事務拆分為多個本地事務,每個本地事務都有相應的執行模塊和補償模塊( TCC中的Confirm和Cancel)。當Saga事務中任意一個本地事務出錯時,可以通過調用相關的補償方法恢復之前的事務,達到事務最終的一致性。
當每個Saga子事務 T1, T2, …, Tn 都有對應的補償定義 C1, C2, …, Cn-1,那么Saga系統可以保證:
-
子事務序列?T1, T2, …, Tn得以完成?(最佳情況);
-
或者序列?T1, T2, …, Tj, Cj, …, C2, C1, 0 < j < n, 得以完成。
由于Saga模型中沒有Prepare階段,因此事務間不能保證隔離性,當多個Saga事務操作同一資源時,就會產生更新丟失、臟數據讀取等問題,這時需要在業務層控制并發,例如:
-
在應用層面加鎖;
-
應用層面預先凍結資源。
Saga恢復方式
Saga支持向前和向后恢復:
-
向后恢復:補償所有已完成的事務,如果任一子事務失敗;
-
向前恢復:重試失敗的事務,假設每個子事務最終都會成功。
顯然,向前恢復沒有必要提供補償事務,如果你的業務中,子事務(最終)總會成功,或補償事務難以定義或不可能,向前恢復更符合你的需求。理論上補償事務永不失敗,然而,在分布式世界中,服務器可能會宕機、網絡可能會失敗,甚至數據中心也可能會停電,這時需要提供故障恢復后回退的機制,比如人工干預。
總的來說,TCC和MQ都是以服務為范圍進行分布式事務的處理,而XA、BED、SAGA則是以數據庫為范圍進行分布式處理,我們更趨向于選擇后者,對于業務而言侵入小,改造的成本低。
Sharding-Sphere對分布式事務的支持
Sharding-Sphere是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar這3款相互獨立的產品組成。它們均提供標準化的數據分片、讀寫分離、柔性事務和數據治理功能,可適用于如Java同構、異構語言、容器、云原生等各種多樣化的應用場景。
項目地址:
https://github.com/sharding-sphere/sharding-sphere/
Sharding-Sphere同時支持XA和柔性事務,它允許每次對數據庫的訪問,可以自由選擇事務類型。分布式事務對業務操作完全透明,極大地降低了引入分布式事務的成本。
01
事務模型
?
Sharding-Sphere事務管理器集成了XA和柔性事務模型:
-
對于XA事務而言,采用SPI的方式讓弱XA、Atomikos、Narayana間保持互斥;
-
對于柔性事務而言,根據每次連接中事務的類型,可以選擇獨立的事務管理器進行處理,每個事務管理器都會實現標準的ShardingTransaction接口,在TransactionEvent到來時,執行對應的begin、commit、rollback操作。
下面將Sharding-Sphere內部如何用事件驅動方式,將事務從分片主流程中解耦進行詳細說明:
從圖可以看出在Sharding-core在調用執行引擎時,會根據SQL的種類產生事件進行分發。事務監聽線程在收到符合要求的事件后,再調用對應的事務處理器進行處理。
02
Sharding-Proxy事務實現
Sharding-Proxy是基于netty開發的數據庫中間代理層,實現了標準的MySQL協議,可以看做是一個實現了數據分片的數據庫。Sharding-Proxy已經實現了基于Atomikos的XA事務,為了保證所有的子事務都處于同一個線程之中,整個Proxy的線程模型進行了如下的調整:
?
當開啟事務后,Proxy后端的SQL命令執行引擎將采用一通道一線程的模式,此事務線程的生命周期同通道保持一致。事務處理的具體過程與Proxy徹底解耦,即Proxy將發布事務類型的事件,然后Sharding-Sphere-TM根據傳入的事務消息,選擇具體的TM進行處理。
壓測結果表明:XA事務的插入和更新的性能,基本上同跨庫的個數呈線性關系,查詢的性能基本不受影響,建議在并發量不大,每次事務涉及的庫在10個以內時,可以使用XA。
?
Atomikos事務管理器原理分析
?
Atomikos的事務管理器可以內嵌到業務進程中,當應用調用TransactionManager.begin時,將會創建本次XA事務,并且與當前線程關聯。同時Atomikos也對DataSource中的connection做了二次封裝,代理connection中含有本次事務相關信息的狀態,并且攔截了connection的JDBC操作。
在createStatement時,調用XAResource.start進行資源注冊;在close時,調用XAResource.end讓XA事務處于idel可提交狀態;在commit或rollback時,依次調用prepare和commit進行二階段提交。
Sharding-Sphere的Saga事務實現
Sharding-Sphere通過與Apache Service Comb的合作,將采用Service Comb的Saga事務引擎作為的分布式事務實現。
Apache Service Comb是華為開源的微服務框架,其中微服務事務處理框架分為集中式和分布式協調器。未來會在Sharding-Sphere內部集成Saga集中式協調器,支持同一線程內不同服務(本地)間的分布式事務。
參考鏈接:
https://github.com/apache/incubator-servicecomb-saga
Service Comb 集中式事務協調器
集中式的協調器,包含了Saga調用請求接收、分析、執行以及結果查詢的內容。任務代理模塊需要預先知道Saga事務調用關系圖,執行模塊根據生成的調用圖產生調用任務,調用相關微服務服務接口。如果服務調用執行出錯,會調用服務的相關的補償方法回滾。
Saga執行模塊通過分析請求的JSON數據,來構建一個調用關系圖。Sharding-Sphere是通過JSON描述Saga事務串行調用子事務或者并行調用子事務。關系調用圖被Saga實現中的任務運行模塊分解成為一個一個執行任務,執行任務由任務消費者獲取并生成相關的調用 (同時支持串行和并行調用)。Saga任務會根據執行的情況向Saga Log中記錄對應的Saga事務的關鍵事件,并可以通過事件查看器查查詢執行情況。
Sharding-Sphere內嵌Saga事務管理器
Saga以jar包的形式提供分布式事務治理能力。
對Sharding-Sphere而言,confirm和cancel過程代表了子事務中的正常執行SQL和逆向執行SQL,(未來Sharding-Sphere將提供自動生成逆向SQL的能力)。當啟用Saga柔性事務后,路由完成之后的物理數據源將開啟本地自動提交事務,每次confirm和cancel都會直接提交。
在Sharding-Sphere內部,觸發SQL執行引擎后,將會產生Saga事務事件,這時Sharding-Sphere事務監聽器會注冊本次子事務的confirm和cancel至Saga事務管理器的隊列中;在業務線程觸發commit和rollback后,Saga事務管理器再根據子事務執行的結果,判斷進行confirm重試或者cancel流程。
未來計劃
未來Sharding-Sphere將按照文中介紹的Sharding-Sphere-TM逐步完善整個事務框架:
-
弱XA事務 (已發布)
-
基于Atomikos的XA事務(近期發布)
-
基于Narayana的XA事務(規劃中)
-
BED柔性事務(已發布)
-
SAGA(開發中)
-
TCC(規劃中)
如果前面的分享太過冗長,那么千言萬語匯聚成一張表格,歡迎閱讀。
未來,我們將不斷優化當前的特性,陸續推出大家關注的柔性事務、數據治理等更多新特性。如果有什么想法、意見和建議,也歡迎留言交流,更歡迎加入到Sharding-Sphere的開源項目中:
-
https://github.com/sharding-sphere/sharding-sphere/
-
https://gitee.com/sharding-sphere/sharding-sphere/
總結
以上是生活随笔為你收集整理的分布式事务在Sharding-Sphere中的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信“看一看“个性化推荐:排序篇
- 下一篇: 旅行场景下的个性化营销平台揭秘