Zookeeper概念學習系列之分布式事務


 

 

    不多說,直接上干貨!

 

  初學者來說,肯定會有這么一個疑問。為什么會在zookeeper里牽扯到分布式事務?

 

 

 

zookeeper到底是什么?

  zookeeper實際上是yahoo開發的,用於分布式中一致性處理的框架。最初其作為研發hadoop時的副產品。由於分布式系統中一致性處理較為困難,其他的分布式系統沒有必要 費勁重復造輪子,故隨后的分布式系統中大量應用了zookeeper,以至於zookeeper成為了各種分布式系統的基礎組件,其地位之重要,可想而知。著名的hadoop,kafka,dubbo 都是基於zookeeper而構建。
  要想理解zookeeper到底是做啥的,那首先得理解清楚,什么是一致性。
  所謂的一致性,實際上就是圍繞着“看見”來的。誰能看見?能否看見?什么時候看見?舉個例子:淘寶后台賣家,在后台上架一件大促的商品,通過服務器A提交到主數據庫,假設剛提交后立馬就有用戶去通過應用服務器B去從數據庫查詢該商品,就會出現一個現象,賣家已經更新成功了,然而買家卻看不到;而經過一段時間后,主數據庫的數據同步到了從數據庫,買家就能查到了。
  假設賣家更新成功之后買家立馬就能看到賣家的更新,則稱為強一致性
  如果賣家更新成功后買家不能看到賣家更新的內容,則稱為弱一致性
  而賣家更新成功后,買家經過一段時間最終能看到賣家的更新,則稱為最終一致性

 

 

  更詳細,見

Zookeeper概念學習系列之zookeeper是什么?

 

 

 

 

 

 

 

 

分布式事務

  我們首先考慮一致性的特殊情況,即分布式事務的情況。分布式事務對於一致性的要求是強一致性,因此對於我們后續討論有一定的借鑒意義。

  這里我們用到一個經典的例子:bob給smith轉賬,強一致性的要求一定是需要對外來說bob減錢的同時smith加錢

  因為假設賣家更新成功之后買家立馬就能看到賣家的更新,則稱為強一致性;

 

 

  單機環境下是這樣的:

  簡單講就是有關bob的減錢和smith的加錢都轉同一個庫來做,可以采用數據庫的事務特性輕松支持。保證bob給smith轉賬的安全性。

 

 

 

  而分布式環境就變這樣了:

  假設應用服務器是A,bob端的數據庫是B,smith端的數據是C,那么A做成一個轉賬,需要B事務成功提交,並且C事務成功提交。然而因為網絡的影響,可能出現兩種情況:

  1. 如果bob扣款成功,而網絡通知smith失敗了,則會出現bob的錢減了,smith的錢沒加
  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在工業界的應用,是相當了不起的設計,通過各種方式規避了各種可能的不一致性,在性能,效率等方面做到了平衡。

 

  分布式開放消息系統(RocketMQ)的原理與實踐 http://www.jianshu.com/p/453c6e7ff81c


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM