提起微服務架構,不可避免的兩個話題就是服務治理和分佈式事務。數據庫和業務模塊的垂直拆分爲咱們帶來了系統性能、穩定性和開發效率的提高的同時也引入了一些更復雜的問題,例如在數據一致性問題上,咱們再也不可以依賴數據庫的本地事務,對於一系列的跨庫寫入操做,如何保證其原子性,是微服務架構下不得不面對的問題。算法
1 分佈式事務解決方案數據庫
針對分佈式系統的特色,基於不一樣的一致性需求產生了不一樣的分佈式事務解決方案,追求強一致的兩階段提交、追求最終一致性的柔性事務和事務消息等等。各類方案沒有絕對的好壞,拋開具體場景咱們沒法評價,更沒法能作出合理選擇。在選擇分佈式事務方案時,須要咱們充分了解各類解決方案的原理和設計初衷,再結合實際的業務場景,從而作出科學合理的選擇。架構
2 強一致解決方案併發
2.1 兩階段提交分佈式
兩階段提交算法中有兩種角色:事務協調者和事務參與者,一個事務通常會涉及多個事務參與者,具體的兩階段過程以下圖所示:ide
第一階段:寫庫操做完成後協調者向全部參與者發送Prepare消息,詢問各參與者的本地事務是否能夠提交,參與者根據自身狀況向協調者返回能夠或不能夠;微服務
第二階段:協調者收到全部參與者的反饋後,若是所有返回的是能夠提交則向全部參與者發送提交事務命令。只要有一個參與者返回的是不能提交,則向全部參與者發送回滾命令。以下圖所示:高併發
圖1 兩階段提交性能
在上述的兩階段模型中,事務提交過程當中有可能出現協調者或個別參與者宕機的狀況,但多數狀況下參與事務的節點能夠經過詢問其餘節點得知事務狀態,作出正確的操做。但在極端狀況下事務有可能處於未知狀態。咱們分析下下面這個場景:當協調者發送提交指令後宕機,而惟一收到提交指令的參與者完成提交後也宕機了,此時沒有節點知道事務應該提交仍是回滾,事務處於未知狀態,因此在這種極端狀況下可能形成數據的不一致。針對兩階段的缺陷,又提出了三階段提交協議。設計
2.2 三階段提交
三階段提交是將第二階段拆分紅預提交和確認提交兩個階段。這樣在事務提交過程當中,不管哪一個節點宕機,只要有一個存活節點處於預提交或是提交狀態咱們均可以肯定事務是能夠提交的(第一階段已經確認事務能夠提交),反之若是沒有處於這兩種狀態的節點,則回滾事務。
圖2 三階段提交
從上面的分析能夠看到,不管是兩階段仍是三階段最後的「提交」都是一個耗時極短的操做,即便在分佈式系統中失敗的機率也是很是小的,因此咱們能夠認爲兩階段提交基本可以保證分佈式事務原子性。
3 落地方案
上面介紹的只是理論基礎,XA規範就是基於兩階段提交的理論模型提出的分佈式事務規範,規範中的資源管理器至關於事務參與者;事務管理器至關於事務協調者,目前不少主流的關係數據庫都實現了XA接口。
落地到實際應用中咱們會發現兩階段提交存在的一些問題:
數據庫產品要保證數據完成性,寫入須要加鎖,因此在整個分佈式事務協調過程當中可能形成數據庫資源鎖定時間過長,不適合併發高以及子事務生命週期較長的業務場景;
XA可以最大程度保證數據的一致性,但在高併發場景下性能衰減很是嚴重,因此在數據一致性需求上若是不是「強一致」,不建議使用。
3.1 最終一致性解決方案
在咱們大多數的業務場景中,追求的都是數據的最終一致性,業界也提出了不少柔性事務的解決方案,能夠很大程度上保證數據的一致性,咱們能夠根據實際場景來權衡使用。具體的解決方案有不少,總結其設計思路能夠分爲下面3種模型:
3.1.1 TCC(Try-Confirm-Cancel)
TCC將事務分爲Try,Confirm,Cancel三個階段。
Try階段:嘗試執行業務,預留資源;
Confirm階段:確認執行業務,使用Try階段資源;
咱們用一個轉帳匯款的業務場景,說明下TCC的具體過程。例如:張三給李四轉帳100元,一次轉帳業務由兩個本地事務組成:一、張三帳戶扣減100元;二、李四帳戶增長100元。
事務成功處理流程如圖3:
圖3 Try-Confirm事務成功處理流程
事務失敗處理流程如圖4:
圖4 Try-Cancel事務成功處理流程
Try階段:
一、檢查張三帳戶,知足要求帳戶扣減100元,記錄扣減事件(預留資源);
二、檢查李四帳戶有效性;
Confirm:
若是Try成功,李四帳戶增長100元,事務完成;
Cancel:
若是Try失敗,張三帳戶增長100元,刪除扣減事件記錄(釋放預留資源),事務取消。
從性能角度分析,TCC過程沒有對資源加鎖,對系統併發性能幾乎沒有影響,只是會有些額外輔助操做。須要注意,在這個模型中要保證數據一致性有兩個技術難點須要解決:
須要有相似事務管理器的角色保證TCC過程的完整性;
TCC對業務侵入很是大,對RD同窗十分不友好,業務改形成本至關高。
3.1.2 SAGA模型
SAGA模型把一個分佈式事務拆分爲多個本地事務,每一個本地事務都有相應的執行模塊和補償模塊,當事務中任意一個本地事務出錯時,能夠經過調用對應的補償方法恢復以前的事務,從而達到數據的最終的一致性。SAGA的事務管理器負責在事務失敗時執行補償邏輯,能夠經過調用執行模塊的逆向操做(例如執行子事務時同時生成逆向SQL)或調用業務開發人員提供的補償方法(須要保證補償的冪等性)來實現。
能夠看到,SAGA雖然對業務形成必定的侵入,但當相對TCC已經有好不少了,並且,事務管理器理論上能夠作到向後補償(撤銷全部已完成操做,恢復到事務開始狀態)或向前補償(繼續完成未完成事務,使業務請求獲得成功處理,更符合業務預期)。
3.1.3 MQ事務消息
MQ事務消息對分佈式事務模型進行了簡化,重點再也不是保證全部子事務的原子性,而是保證本地事務和發送MQ消息的原子性,咱們能夠利用這一特色,將分佈式事務轉化成本地事務和若干發送MQ消息的操做,而後要求消費方確保消費成功。利用MQ事務消息,在系統中去掉了TCC和SAGA方案中的事務管理器角色,簡化了分佈式事務模型,同時這也是對業務侵入最低最友好的方案(不用提供補償接口)。
固然這裏也有兩個基本前提:
MQ系統保證消息能不丟失;
須要注意的是,MQ事務消息簡化了事務模型、下降了業務侵入,因此對數據一致性的保證保障也就相對比較低了。
柔性事務解決方案中,雖然SAGA和TCC看上去能夠保證數據的最終一致性,但分佈式系統的成產環境複雜多變,某些狀況是能夠致使柔性事務機制失效的,因此不管使用那種方案,都須要最終的兜底策略,人工校驗,修復數據。
咱們綜合對比下幾種分佈式事務解決方案:
一致性保證:XA > TCC = SAGA > 事務消息
業務友好性:XA > 事務消息 > SAGA > TCC
性 能 損 耗:XA > TCC > SAGA = 事務消息
最後,在設計系統時咱們必定要結合業務自身的一致性需求,選擇恰當的方案。能夠看到對數據一致性保障越高的方案其開發成本、維護難度和系統性能損耗就越大,必定不要一味的追求高大上的方案,對系統過分設計。
更多免費技術資料及視頻