2PC
這種不一致的問題困擾着大家。任意一邊出錯想要回滾另一邊都不是簡單的數據庫回滾的事情( 因爲此時已經成功提交),而是需要做業務的逆向操作,而不同業務的逆操作都不同,導致複雜性增加。考慮數據庫事務的執行實際上是先將執行操作寫入binlog,等到最後通過一個commit指令將binlog的內容一次更新到表中,或者寫到一半通過一個rollback指令將binlog中的內容回滾。於是乎,可以想到使用2個階段來執行這個過程,第一階段,寫入binlog;第二階段執行commit或者rollback。這就是著名的兩階段提交協議(2PC)。如果仔細考慮,會發現兩階段協議並沒有解決問題,只不過降低了出錯的概率而已,因爲第二階段同樣存在上面的兩種情況。注意最終狀態是多臺機器的狀態&&的 結果。以下是兩階段協議的時序圖:
1. 考慮prepare階段的響應(因爲請求階段和執行階段都可以在最後響應中體現出來),對於分佈式環境中,任意時刻考慮3種狀態:成功、失敗、超時。
a.成功。不必處理,執行後續行爲commit。
b.失敗。這是執行階段出錯,執行後續行爲rollback。
c.超時。這可能是執行階段太慢,也可能是網絡階段太慢或丟包,但是保守處理,超時可以當做出錯。
可以看出,prepare階段的問題能夠完全避免。
2. 考慮commit階段,同樣考慮成功失敗超時3種狀態。
a. 成功。整個事務成功執行
b. 失敗。提交出錯,假設此時前面的B已經提交成功了,則同樣面臨需要回滾B卻無法回滾的問題,因爲B已經提交成功了。
c. 超時。同上。
還有一種例外情況,即prepare階段完成後A掛了,則B,C即進入不知所措的狀態。
可以看出,在2PC中事務無法做到像單機一樣安全,只不過降低了出問題的概率。
3PC
針對如何解決2PC中的例外情況,出現了3階段提交協議。3階段的主要改進是把2階段的prepare再分爲canCommit和preCommit兩個階段。
1. 考慮cancommit階段的響應。
a.成功。不必處理,執行後續行爲precommit。
b.失敗。說明無法執行,無須後續提交或回滾行爲。
c.超時。保守處理,超時可以當做失敗。
2. 考慮precommit階段的響應。
a.成功。不必處理,執行後續行爲docommit。
b.失敗。執行階段出錯,執行後續行爲rollback。
c.超時。執行階段太慢,也可能是網絡階段太慢或丟包,但是保守處理,超時可以當做出錯。
3. 考慮cancommit階段的響應。
a.成功。整個事務成功執行。
b.失敗。提交出錯,假設此時前面的B已經提交成功了,則同樣面臨無法回滾的問題。
c.超時。保守處理,超時可以當做失敗。
XTS
工業界的對分佈式事務的應用是如何呢?可以參考某寶的知名分佈式框架XTS。
XTS本質上是2PC(實際上如果引入3PC會多2n次網絡交互,在量大時反而更加不安全)。XTS引入協調者A的server部分,實際上是一個大集羣,以配置的方式接入各種需要分佈式事務的業務,集羣由專門的團隊維護,保證其可用性和性能;而協調者A的client部分則通過發起方調用,prepare階段時,先通過client將本次事務信息發送到server,落庫,然後即時推送prepare請求到B和C,當收到B,C的響應時把他們狀態入庫,如果正常,則做commit提交;否則會用定時任務去推送未完成的狀態直到完成。上文提到的prepare之後協調者A掛了這種情況,在server集羣的保證下,幾乎很少會發生。而上文提到的所有超時的情況,都可以通過定時任務推送拿到一個確定的狀態而不是盲目的選擇回滾或者提交。另外由於B和C都是集羣,很少會發生多次請求過去無響應的情況。直到最後一種情況就是commit時B成功了C失敗了,或者反過來B失敗C成功,這種情況成爲懸掛事務,最終等待人工來解決,據說每天都有幾筆到幾十筆。
無疑XTS作爲2PC在工業界的應用,是相當了不起的設計,通過各種方式規避了各種可能的不一致性,在性能,效率等方面做到了平衡。
TCC(Try/Confirm/Cancel)
業務補償類型,其基本思想是對每一個業務操作做一個逆操作,一旦成功了,就做正向業務,一旦失敗了就做業務的逆操作。通常在業務邏輯簡單並且正逆操作清晰的時候用比較好。
查詢補償
典型的場景是向銀行發送了轉賬請求未得到明確的成功失敗返回碼,此時先做業務結果的查詢,根據結果做相應處理,比如查詢結果成功,則置狀態爲成功,查詢結果失敗,則做相應的業務補償,查詢結果爲未知,則繼續查詢。
消息事務及消息重試
事務消息及消息重試本質上都是將一些通用的事務交給消息中間件,通過消息中間件來保證消息的最終一致性。
事實上,消息事務解決了這類問題,即本地事務和消息應當有一致性,解決這個一致性比較麻煩,比如消息中間件和業務同時實現XA;或者採用一些更加複雜的方式,比如將消息表與業務表放同庫,利用數據庫的事務來保證一致性,而消息系統只需要輪訓該消息表即可;當然,也有消息的二階段提交+補償的方式。消息事務解決了消息發起方,即生產者與消息中間件之間的一致性問題。
- try{
- //數據庫操作
- //消息投遞
- }catch(Exception e){
- //回滾
- }
分佈式開放消息系統(RocketMQ)的原理與實踐 http://www.jianshu.com/p/453c6e7ff81c
消息中間件(一)分佈式系統事務一致性解決方案大對比,誰最好使? http://blog.csdn.net/lovesomnus/article/details/51785108