相比於資料分片方案的逐漸成熟,集效能、透明化、自動化、強一致、並能適用於各種應用場景於一體的分散式事務解決方案則顯得鳳毛麟角。基於兩(三)階段提交的分散式事務的效能瓶頸以及柔性事務的業務改造問題,使得分散式事務至今依然是令架構師們頭疼的問題。
Apache ShardingSphere(Incubating)不失時機的在2019年初,提供了一個剛柔並濟的一體化分散式事務解決方案。如果您的應用系統正在受到這方面的困擾,不妨倒上一杯咖啡,花十分鐘閱讀此文,說不定會有些收穫呢?
資料庫事務需要滿足ACID(原子性、一致性、隔離性、永續性)4個特性。
原子性(Atomicity)指事務作為整體來執行,要麼全部執行,要麼全不執行。 一致性(Consistency)指事務應確保資料從一個一致的狀態轉變為另一個一致的狀態。 隔離性(Isolation)指多個事務併發執行時,一個事務的執行不應影響其他事務的執行。 永續性(Durability)指已提交的事務修改資料會被持久儲存。
在單一資料節點中,事務僅限於對單一資料庫資源的訪問控制,稱之為本地事務。幾乎所有的成熟的關係型資料庫都提供了對本地事務的原生支援。 但是在基於微服務的分散式應用環境下,越來越多的應用場景要求對多個服務的訪問及其相對應的多個資料庫資源能納入到同一個事務當中,分散式事務應運而生。
關係型資料庫雖然對本地事務提供了完美的ACID原生支援。 但在分散式的場景下,它卻成為系統效能的桎梏。如何讓資料庫在分散式場景下滿足ACID的特性或找尋相應的替代方案,是分散式事務的重點工作。
★本地事務★
在不開啟任何分散式事務管理器的前提下,讓每個資料節點各自管理自己的事務。 它們之間沒有協調以及通訊的能力,也並不互相知曉其他資料節點事務的成功與否。 本地事務在效能方面無任何損耗,但在強一致性以及最終一致性方面則力不從心。
★兩階段提交★
XA協議最早的分散式事務模型是由X/Open國際聯盟提出的X/Open Distributed Transaction Processing(DTP)模型,簡稱XA協議。
基於XA協議實現的分散式事務對業務侵入很小。 它最大的優勢就是對使用方透明,使用者可以像使用本地事務一樣使用基於XA協議的分散式事務。 XA協議能夠嚴格保障事務ACID特性。
嚴格保障事務ACID特性是一把雙刃劍。 事務執行在過程中需要將所需資源全部鎖定,它更加適用於執行時間確定的短事務。 對於長事務來說,整個事務進行期間對資料的獨佔,將導致對熱點資料依賴的業務系統併發效能衰退明顯。 因此,在高併發的效能至上場景中,基於XA協議兩階段提交型別的分散式事務並不是最佳選擇。
★柔性事務★
如果將實現了ACID的事務要素的事務稱為剛性事務的話,那麼基於BASE事務要素的事務則稱為柔性事務。 BASE是基本可用、柔性狀態和最終一致性這3個要素的縮寫。
基本可用(Basically Available)保證分散式事務參與方不一定同時線上。 柔性狀態(Soft state)則允許系統狀態更新有一定的延時,這個延時對客戶來說不一定能夠察覺。 最終一致性(Eventually consistent)通常是透過訊息傳遞的方式保證系統的最終一致性。
在ACID事務中對一致性和隔離性的要求很高,在事務執行過程中,必須將所有的資源佔用。 柔性事務的理念則是透過業務邏輯將互斥鎖操作從資源層面上移至業務層面。透過放寬對強一致性和隔離性的要求,只要求當整個事務最終結束的時候,資料是一致的。而在事務執行期間,任何讀取操作得到的資料都有可能被改變。這種弱一致性的設計可以用來換取系統吞吐量的提升。
Saga是典型的柔性事務管理器。Sagas這個概念來源於三十多年前的一篇資料庫論文[http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf] ,一個Saga事務是一個有多個短時事務組成的長時的事務。 在分散式事務場景下,我們把一個Saga分散式事務看做是一個由多個本地事務組成的事務,每個本地事務都有一個與之對應的補償事務。在Saga事務的執行過程中,如果某一步執行出現異常,Saga事務會被終止,同時會呼叫對應的補償事務完成相關的恢復操作,這樣保證Saga相關的本地事務要麼都是執行成功,要麼透過補償恢覆成為事務執行之前的狀態。
TCC(Try-Cancel/Confirm實現)是另一種柔性事務的協調實現。TCC藉助兩階段提交協議提供了一種比較完美的恢復方式。在TCC方式下,cancel補償顯然是在第二階段需要執行業務邏輯來取消第一階段產生的後果。Try是在第一階段執行相關的業務操作,完成相關業務資源的佔用,例如預先分配票務資源,或者檢查並掃清使用者賬戶信用額度。 在取消階段釋放相關的業務資源,例如釋放預先分配的票務資源或者恢復之前佔用的使用者信用額度。 那我們為什麼還要加入確認操作呢?這需要從業務資源的使用生命週期來入手。在try過程中,我們只是佔用的業務資源,相關的執行操作只是出於待定狀態,只有在確認操作執行完畢之後,業務資源才能真正被確認。
基於ACID的強一致性事務和基於BASE的最終一致性事務都不是銀彈,只有在最適合的場景中才能發揮它們的最大長處。可透過下表詳細對比它們之間的區別,以幫助開發者進行技術選型。
本地事務 兩階段提交 柔性事務 業務改造 無 無 實現相關介面 一致性 不支援 支援 最終一致 隔離性 不支援 支援 業務方保證 併發效能 無影響 嚴重衰退 略微衰退 適合場景 業務方處理不一致 短事務 & 低併發 長事務 & 高併發
★挑戰★
由於應用的場景不同,需要開發者能夠合理的在效能與功能之間權衡各種分散式事務。
兩階段提交與柔性事務的API和功能並不完全相同,在它們之間並不能做到自由的透明切換。在開發決策階段,就不得不在兩階段提交的事務和柔性事務之間抉擇,使得設計和開發成本被大幅增加。
基於XA的兩階段提交事務使用相對簡單,但是無法很好的應對網際網路的高併發或複雜系統的長事務場景;柔性事務則需要開發者對應用進行改造,接入成本非常高,並且需要開發者自行實現資源佔用和反向補償。
整合現有的成熟事務方案,為本地事務、兩階段提交和柔性事務提供統一的分散式事務介面,並彌補當前方案的不足,提供一站式的分散式事務解決方案是Apache ShardingSphere(Incubating)分散式事務模組的主要設計標的。該模組的名稱是sharding-transaction。可以用剛柔並濟、自動化和透明化這3個關鍵詞來概括sharding-transaction模組的設計理念和功能呈現。
1. 剛柔並濟
同時提供基於XA的兩階段提交事務與基於Saga的柔性事務解決方案,並且能夠一起配合使用。
2. 自動化
XA事務和Saga事務都透過自動化的方式完成,使用方無感知。XA事務無需使用XADataSource介面以及JTA事務管理器;Saga事務也無需使用者自行實現補償介面。
3. 透明化
在Apache ShardingSphere(Incubating)的兩個接入端——Sharding-JDBC和Sharding-Proxy中,分別提供了面向本地事務介面的封裝。使用方完全可以將被ShardingSphere管理的水平分片的多個資料源當成一個資料庫使用,透過本地事務API即可實現完全的分散式事務的能力。使用者可以透明地在應用中任意切換事務型別。
sharding-transaction模組由sharding-transaction-core,sharding-transaction-2pc和sharding-transaction-base這3個子模組組成。
sharding-transaction-core:
提供了面向使用者的API與面向開發者的SPI。
sharding-transaction-2pc:
兩階段提交事務父模組。目前只有sharding-transaction-xa模組,提供了XA協議的支援。未來會引入更多的基於兩階段提交的事務型別,如:percolator,參見: [https://storage.googleapis.com/pub-tools-public-publication-data/pdf/36726.pdf]。
sharding-transaction-base:
柔性事務父模組。目前只有sharding-transaction-saga模組,採用Apache ServiceComb Saga Actuator提供的Saga執行器提供柔性事務支援,併在其基礎之上提供了反向SQL和快照的能力,並由此實現自動逆向補償功能。
下麵將對ShardingSphere的XA和Saga事務模組的功能亮點進行說明。
★XA事務——三大XA事務管理器共護航★
成熟的XA事務管理器非常多,Apache ShardingSphere(Incubating)並未選擇重新造輪子,而是寄望於打造一個生態,將合適的輪子有機地整合在一起,提供成熟穩定的分散式事務處理能力。它的主要功能如下:
1. 復用成熟引擎,自動切換底層實現
Sharding-transaction-xa模組進一步定義了面向XA事務管理器開發者的SPI,開發者僅需實現SPI定義的介面,即可自動加入至Apache ShardingSphere(Incubating)生態,作為其XA事務管理器。
Apache ShardingSphere(Incubating)官方目前實現了基於Atomikos和Bitronix的SPI,並且邀請了Radhat JBoss的XA事務引擎Narayana [https://github.com/jbosstm/narayana] 開發團隊實現了JBoss的SPI。使用者可以自行的在Atomikos,Bitronix和Narayana間選擇自己喜歡的XA事務管理器。
受限於Apache基金會專案License的原因,Apache ShardingSphere(Incubating)將採用Apache協議的Atomikos作為其預設實現,關於基於LGPL協議的Bitronix和基於LGPL協議的Narayana,使用者可以自行取用相應jar包至專案的classpath即可。
如果這3個XA事務管理器仍未滿足使用者需求,開發者則可透過擴充套件SPI來實現定製化的XA事務管理器。
2. 資料源透明化自動接入
Apache ShardingSphere(Incubating)能夠自動將XADataSource作為資料庫驅動的資料源接入XA事務管理器。而針對於使用DataSource作為資料庫驅動的應用,使用者也無需改變其編碼以及配置,Apache ShardingSphere(Incubating)透過自動適配的方式,在中介軟體內部將其轉化為支援XA協議的XADataSource和XAConnection,並將其作為XA資源註冊到底層的XA事務管理器中。
XA模組的架構圖如下:
★Saga事務—跨越柔性事務限制,實現自動補償★
在柔性事務中,每一次對資料庫的更新操作都將資料真正的提交至資料庫,以達到高併發系統中最佳資源釋放的效果。當資料出現問題需要回滾時,透過柔性事務管理器保持資料的最終一致性以及隔離行為。Apache ShardingSphere(Incubating)採用Apache ServiceComb Saga Actuator [https://github.com/apache/servicecomb-saga-actuator] 作為Saga事務管理器,它的主要功能如下:
1. 自動反向補償
Saga定義了一個事務中的每個子事務都有一個與之對應的反向補償操作。由Saga事務管理器根據程式執行結果生成一張有向無環圖,併在需要執行回滾操作時,根據該圖依次按照相反的順序呼叫反向補償操作。Saga事務管理器只用於控制何時重試,合適補償,並不負責補償的內容,補償的具體操作需要由開發者自行提供。
另一個柔性事務管理器TCC與Saga理念相似,均需要由使用方開發者提供補償操作。除了補償,TCC還提供了資源佔用的能力,但也需要由使用方開發者提供資源佔用操作。雖然功能上強於Saga,但TCC的使用成本較之Saga也更高。
由使用方開發者提供資源佔用和補償操作,這就使得柔性事務的解決方案始終難於大規模的在業務系統中落地。並且由於業務系統的介入,使得柔性事務框架的使用範疇始終定位於服務而非資料庫,資料庫能夠直接使用的成熟的柔性事務管理器目前還不多見。
Apache ShardingSphere(Incubating)採用反向SQL技術,將對資料庫進行更新操作的SQL自動生成資料快照以及反向SQL,並交由Apache ServiceComb Saga Actuator執行,使用方則無需再關註如何實現補償方法,將柔性事務管理器的應用範疇成功的定位回了事務的本源——資料庫層面。
對於能夠處理複雜查詢陳述句的Apache ShardingSphere(Incubating)SQL解析引擎來說,插入/更新/刪除等陳述句解析難度則要小很多;ShardingSphere是透過攔截使用者執行的SQL進行資料分片的,所有的SQL都能夠被其直接管控。因此將反向SQL和補償能力與Apache ServiceComb Saga Actuator相結合,達到了自動化柔性事務的能力,是資料分片和柔性事務結合的典範。
Saga模組的架構圖如下:
★接入端—面向原生事務介面的分散式事務★
Apache ShardingSphere(Incubating)的標的是像使用一個資料庫一樣使用分片後的多資料庫,在事務模組,這個標的依然適用。無論被ShardingSphere所管理的資料庫如何分片,面向開發者的邏輯資料庫始終只有一個。因此,ShardingSphere的事務介面依然是原生的本地事務介面,即JDBC的java.sql.Connection的setAutoCommit, commit和rollback方法;以及面向資料庫事務管理器的begin, commit和rollback陳述句。在使用者呼叫原生本地事務介面的同時,ShardingSphere則透過sharding-transaction模組保證後端分片資料庫的分散式事務。
由於原生的事務介面並不支援事務型別,因此ShardingSphere提供了3種方式供使用者切換事務型別。
1. 透過SCTL(sharding-ctl,即ShardingSphere提供的資料庫管理命令)切換當前事務型別。以SQL執行的方式輸入即可,適用於Sharding-JDBC和Sharding-Proxy。例如:SCTL:SET TRANSACTION_TYPE=BASE
2. 透過Threadlocal切換當前事務型別,適用於Sharding-JDBC。例如:TransactionTypeHolder.set (TransactionType.XA) 3. 透過元註解,並與Spring配合使用切換當前事務型別,適用於Sharding-JDBC和Sharding-Proxy。例如:@ShardingTransactionType (TransactionType.BASE)
分散式事務模組在github的開發分支 [https://github.com/apache/incubator-shardingsphere] 已經基本可用,將隨著4.0.0.M1的版本釋出,這也將是ShardingSphere進入Apache基金會孵化器之後的第一個釋出版本。分散式事務是資料分片以及微服務架構的重要組成部分,也是Apache ShardingSphere(Incubating)的關註重心,釋出之後仍將繼續完善,線路規劃如下。
★事務隔離引擎★
在SQL反向引擎穩定之後,柔性事務的重點將放在打造事務隔離之上。由於事務的隔離性並非Saga所規劃的範疇,因此Apache ShardingSphere(Incubating)會在Saga之外將其完善,與SQL反向引擎一起作為整個柔性事務的組成部分。
Apache ShardingSphere(Incubating)將透過樂觀鎖、悲觀鎖、無隔離等幾種策略,做到讀已提交、讀未提交、可重覆讀以及序列化等隔離級別的一一支援。並透過多版本快照進一步提升系統的併發度。
★對外XA事務介面★
Apache ShardingSphere(Incubating)的兩個接入端Sharding-JDBC和Sharding-Proxy在支援自身的內部事務問題之後,將提供融入與其他資料源一起作為被JTA等分散式事務管理器管理的能力。
實現對外XA事務介面之後,Sharding-JDBC的DataSource將實現XADataSource介面,提供與其他資料源共同加入到一個XA事務的可能;Sharding-Proxy的資料庫協議也將實現基於XA的兩階段提交協議;使其可以成為被XA所載入的資源管理器。
除此之外,ShardingSphere還會實現XA協議的recovery部分,即在事務處理器出現崩潰的情況時,可以有能力提供in-doubt transactions來實現事務恢復。
Apache ShardingSphere(Incubating)提供的分散式事務能力可以透過下表總結一下,讀者不妨與文章開始時的表格對比一下,看看ShardingSphere的分散式事務模組所帶來的變化。 本地事務 兩階段提交 柔性事務 業務改造 無 無 無 一致性 不支援 支援 最終一致 隔離性 不支援 支援 規劃中 併發效能 無影響 嚴重衰退 略微衰退 適合場景 業務方處理不一致 短事務 & 低併發 長事務 & 高併發
在高速發展的Apache ShardingSphere(Incubating)中,分散式事務的雛形已成,我們會儘快將其打造為可用的產品,並持續為社群提供優質解決方案。對於一篇不算短的文章,閱讀完此文的您,相信一定對這個領域有一定興趣。不妨先嘗試一下,是否滿足您的預期?或者乾脆加入我們的社群,一起打造更完善的分散式事務方案。
Apache ShardingSphere(Incubating)自2016開源以來,不斷精進、不斷發展,被越來越多的企業和個人認可:Github上收穫6000+的stars,70+公司企業的成功案例。此外,越來越多的企業和個人也加入到Apache ShardingSphere(Incubating)的開源專案中,為它的成長和發展貢獻了巨大力量。
我們從未停息過腳步,聆聽社群夥伴的需求和建議,不斷開發新的、強大的功能,不斷使其健壯可靠! 開源不易, 我們卻願向著最終的標的,步履不停! 那麼,正在閱讀的你,是否可以助我們一臂之力呢?分享、轉發、使用、交流,以及加入我們,都是對我們最大的鼓勵! 專案地址: https://github.com/apache/incubator-shardingsphere
更多資訊請瀏覽官網: http://shardingsphere.apache.org/