轉自https://blog.csdn.net/liweisnake/article/details/68942165數據庫
上一章咱們瞭解了zookeeper究竟是什麼,這一章重點來看zookeeper當初到底面臨什麼問題?而zookeeper又是如何解決這些問題的?安全
實際上zookeeper主要就是解決分佈式環境下的一致性問題。那麼解決這個問題到底有哪些難點呢?咱們一步一步來闡述和推理這個過程。服務器
分佈式事務網絡
咱們首先考慮一致性的特殊狀況,即分佈式事務的狀況。分佈式事務對於一致性的要求是強一致性,所以對於咱們後續討論有必定的借鑑意義。這裏咱們用到一個經典的例子:bob給smith轉帳,強一致性的要求必定是須要對外來講bob減錢的同時smith加錢。見文獻1(圖片也來源於文獻1)app
單機環境下是這樣的框架
簡單講就是有關bob的減錢和smith的加錢都轉同一個庫來作,能夠採用數據庫的事務特性輕鬆支持。保證bob給smith轉帳的安全性。分佈式
而分佈式環境就變這樣了性能
假設應用服務器是A,bob端的數據庫是B,smith端的數據是C,那麼A作成一個轉帳,須要B事務成功提交,而且C事務成功提交。然而由於網絡的影響,可能出現兩種狀況spa
1. 若是bob扣款成功,而網絡通知smith失敗了,則會出現bob的錢減了,smith的錢沒加.net
2. 若是bob扣款不成功,而smith加錢成功了,則會出現smith錢增長了,可是bob的錢也沒減小
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.超時。保守處理,超時能夠當作失敗。
例外狀況,即自cancommit返回成功後的任意階段A掛掉了,那麼BC一樣可以知道這個事務正在發生(由於cancommit已經提交了足夠信息讓BC知曉此事),因而BC能夠在無A的狀況下繼續執行後續的階段(好比BC投票啓動新的A',並提供A'足夠信息)。因而3PC正好解決了2PC的例外狀況。
可是3PC仍然存在相似2PC的問題,即最後階段失敗或超時一樣有可能出現數據不一致的問題。因此3PC仍然只是下降了發生機率,並無真正解決問題。
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;或者採用一些更加複雜的方式,好比將消息表與業務表放同庫,利用數據庫的事務來保證一致性,而消息系統只須要輪訓該消息表便可;固然,也有消息的二階段提交+補償的方式。消息事務解決了消息發起方,即生產者與消息中間件之間的一致性問題。
[plain] view plain copy
消息中間件與消費者之間的一致性問題則須要經過重試+冪等來解決。消息重試中主要考慮重試次數以及重試時間的閾值變化。
分佈式開放消息系統(RocketMQ)的原理與實踐 http://www.jianshu.com/p/453c6e7ff81c
消息中間件(一)分佈式系統事務一致性解決方案大對比,誰最好使? http://blog.csdn.net/lovesomnus/article/details/51785108
最終一致性 https://zhuanlan.zhihu.com/p/25933039