系統經sharding改造之後,原來單一的資料庫會演變成多個資料庫,如何確保多資料來源同時操作的原子性和一致性是不得不考慮的一個問題。總體上看,目前對於一個分散式系統的事務處理有三種方式:分散式事務、基於Best Efforts 1PC模式的事務以及事務補償機制。我們下面對這三種處理方式一一進行分析。
分散式事務
這是最為人們所熟知的多資料來源事務處理機制。本文並不打算對分散式事務做過多介紹,讀者可參考此文:關於分散式事務、兩階段提交、一階段提交、Best Efforts 1PC模式和事務補償機制的研究 。在這裡只想對分散式事務的利弊作一下分析。
優勢:
1. 基於兩階段提交,最大限度地保證了跨資料庫操作的“原子性”,是分散式系統下最嚴格的事務實現方式。
2. 實現簡單,工作量小。由於多數應用伺服器以及一些獨立的分散式事務協調器做了大量的封裝工作,使得專案中引入分散式事務的難度和工作量基本上可以忽略不計。
劣勢:
系統“水平”伸縮的死敵。基於兩階段提交的分散式事務在提交事務時需要在多個節點之間進行協調,最大限度地推後了提交事務的時間點,客觀上延長了事務的執行時間,這會導致事務在訪問共享資源時發生衝突和死鎖的概率增高,隨著資料庫節點的增多,這種趨勢會越來越嚴重,從而成為系統在資料庫層面上水平伸縮的”枷鎖”, 這是很多Sharding系統不採用分散式事務的主要原因。
基於Best Efforts 1PC模式的事務
與分散式事務採用的兩階段提交不同,Best Efforts 1PC模式採用的是一階段端提交,犧牲了事務在某些特殊情況(當機、網路中斷等)下的安全性,卻獲得了良好的效能,特別是消除了對水平伸縮的桎酷。Distributed transactions in Spring, with and without XA一文對Best Efforts 1PC模式進行了詳細的說明,該文提供的Demo程式碼更是直接給出了在Spring環境下實現一階段提交的多資料來源事務管理示例。不過需要注意的是,原示例是基於spring 3.0之前的版本,如果你使用spring 3.0+,會得到如下錯誤:java.lang.IllegalStateException: Cannot activate transaction synchronization – already active,如果使用spring 3.0+,你需要參考spring-data-neo4j的實現。鑑於Best Efforts 1PC模式的效能優勢,以及相對簡單的實現方式,它被大多數的sharding框架和專案採用。
事務補償機制
對於那些對效能要求很高,但對一致性要求並不高的系統,往往並不苛求系統的實時一致性,只要在一個允許的時間週期內達到最終一致性即可,這使得事務補償機制成為一種可行的方案。事務補償機制最初被提出是在“長事務”的處理中,但是對於分散式系統確保一致性也有很好的參考意義。籠統地講,與事務在執行中發生錯誤後立即回滾的方式不同,事務補償是一種事後檢查並補救的措施,它只期望在一個容許時間週期內得到最終一致的結果就可以了。事務補償的實現與系統業務緊密相關,並沒有一種標準的處理方式。一些常見的實現方式有:對資料進行對帳檢查;基於日誌進行比對;定期同標準資料來源進行同步,等等。
小結
分散式事務,最嚴格的事務實現,但效能是個大問題;Best Efforts 1PC模式,效能與事務可靠性的平衡,支援系統水平伸縮,大多數情況下是最合適的選擇;事務補償機制,只能適用於對事務性要求不高,允許資料“最終一致”即可的系統,犧牲實時一致性,獲得最大的效能回報。