XA: 事務和兩階段提交


本文原文連接: http://blog.csdn.net/bluishglc/article/details/7612811 ,轉載請注明出處!

 

1.XA

 

XA是由X/Open組織提出的兩階段提交協議,分布式事務的規范。XA規范主要定義了(全局)事務管理器(Transaction Manager)和(局部)資源管理器(Resource Manager)之間的接口。XA接口是雙向的系統接口,在事務管理器(Transaction Manager)以及一個或多個資源管理器(Resource Manager)之間形成通信橋梁。XA之所以需要引入事務管理器是因為,在分布式系統中,從理論上講(參考Fischer等的論文),兩台機器理論上無法達到一致的狀態,需要引入一個單點進行協調。事務管理器控制着全局事務,管理事務生命周期,並協調資源。資源管理器負責控制和管理實際資源(如數據庫或JMS隊列)。下圖說明了事務管理器、資源管理器,與應用程序之間的關系:

 

圖1.XA規范下的分布式事務各類參與者之間的關系

 

2.JTA


作為Java平台上事務規范JTA(Java Transaction API)也定義了對XA事務的支持,實際上,JTA是基於XA架構上建模的,在JTA 中,事務管理器抽象為javax.transaction.TransactionManager接口,並通過底層事務服務(即JTS)實現。像很多其他的java規范一樣,JTA僅僅定義了接口,具體的實現則是由供應商(如J2EE廠商)負責提供,目前JTA的實現主要由以下幾種:


1.J2EE容器所提供的JTA實現(JBoss)
2.獨立的JTA實現:如JOTM,Atomikos.這些實現可以應用在那些不使用J2EE應用服務器的環境里用以提供分布事事務保證。如Tomcat,Jetty以及普通的java應用。

 

3.兩階段提交


所有關於分布式事務的介紹中都必然會講到兩階段提交,因為它是實現XA分布式事務的關鍵(確切地說:兩階段提交主要保證了分布式事務的原子性:即所有結點要么全做要么全不做)。所謂的兩個階段是指:第一階段:准備階段和第二階段:提交階段。

 

圖2.兩階段提交示意圖(摘自info發布的《java事務設計策略》一文)



1.准備階段:事務協調者(事務管理器)給每個參與者(資源管理器)發送Prepare消息,每個參與者要么直接返回失敗(如權限驗證失敗),要么在本地執行事務,寫本地的redo和undo日志,但不提交,到達一種“萬事俱備,只欠東風”的狀態。(關於每一個參與者在准備階段具體做了什么目前我還沒有參考到確切的資料,但是有一點非常確定:參與者在准備階段完成了幾乎所有正式提交的動作,有的材料上說是進行了“試探性的提交”,只保留了最后一步耗時非常短暫的正式提交操作給第二階段執行。)

2.提交階段:如果協調者收到了參與者的失敗消息或者超時,直接給每個參與者發送回滾(Rollback)消息;否則,發送提交(Commit)消息;參與者根據協調者的指令執行提交或者回滾操作,釋放所有事務處理過程中使用的鎖資源。(注意:必須在最后階段釋放鎖資源)

將提交分成兩階段進行的目的很明確,就是盡可能晚地提交事務,讓事務在提交前盡可能地完成所有能完成的工作,這樣,最后的提交階段將是一個耗時極短的微小操作,這種操作在一個分布式系統中失敗的概率是非常小的,也就是所謂的“網絡通訊危險期”非常的短暫,這是兩階段提交確保分布式事務原子性的關鍵所在。(唯一理論上兩階段提交出現問題的情況是當協調者發出提交指令后當機並出現磁盤故障等永久性錯誤,導致事務不可追蹤和恢復)

從兩階段提交的工作方式來看,很顯然,在提交事務的過程中需要在多個節點之間進行協調,而各節點對鎖資源的釋放必須等到事務最終提交時,這樣,比起一階段提交,兩階段提交在執行同樣的事務時會消耗更多時間。事務執行時間的延長意味着鎖資源發生沖突的概率增加,當事務的並發量達到一定數量的時候,就會出現大量事務積壓甚至出現死鎖,系統性能就會嚴重下滑。這就是使用XA事務

4.一階段提交(Best Efforts 1PC模式)

不像兩階段提交那樣復雜,一階段提交非常直白,就是從應用程序向數據庫發出提交請求到數據庫完成提交或回滾之后將結果返回給應用程序的過程。一階段提交不需要“協調者”角色,各結點之間不存在協調操作,因此其事務執行時間比兩階段提交要短,但是提交的“危險期”是每一個事務的實際提交時間,相比於兩階段提交,一階段提交出現在“不一致”的概率就變大了。但是我們必須注意到:只有當基礎設施出現問題的時候(如網絡中斷,當機等),一階段提交才可能會出現“不一致”的情況,相比它的性能優勢,很多團隊都會選擇這一方案。關於在spring環境下如何實現一階段提交,有一篇非常優秀的文章值得參考:http://www.javaworld.com/javaworld/jw-01-2009/jw-01-spring-transactions.html?page=5

5.事務補償機制


像best efforts 1PC這種模式,前提是應用程序能獲取所有的數據源,然后使用同一個事務管理器(這里指是的spring的事務管理器)管理事務。這種模式最典型的應用場景非數據庫sharding莫屬。但是對於那些基於web service/rpc/jms等構建的高度自治(autonomy)的分布式系統接口,best efforts 1PC模式是無能為力的,此類場景下,還有最后一種方法可以幫助我們實現“最終一致性”,那就是事務補償機制。關於事務補償機制是一個大話題,本文只簡單提及,以后會作專門的研究和介紹。

 

6.在基於兩階段提交的標准分布式事務和Best Efforts 1PC兩者之間如何選擇

一般而言,需要交互的子系統數量較少,並且整個系統在未來不會或很少引入新的子系統且負載長期保持穩定,即無伸縮要求的話,考慮到開發復雜度和工作量,可以選擇使用分布式事務。對於時間需求不是很緊,對性能要求很高的系統,應考慮使用Best Efforts 1PC或事務補償機制。對於那些需要進行sharding改造的系統,基本上不應再考慮分布式事務,因為sharding打開了數據庫水平伸縮的窗口,使用分布式事務看起來好像是為新打開的窗口又加上了一把枷鎖。

補充:關於網絡通訊的危險期

由於網絡通訊故障隨時可能發生,任何發出請求后等待回應的程序都會有失去聯系的危險。這種危險發生在發出請求之后,服務器返回應答之前,如果在這個期間網 絡通訊發生故障,發出請求一方無法收到回應,於是無法判斷服務器是否已經成功地處理請求,因為收不到回應可能是請求沒有成功地發送到服務器,也可能是服務 器處理完成后的回應無法傳回請求方。這段時間稱為網絡通訊的危險期(In-doubt Time)。很顯然,網絡通訊的危險期是分布式系統除單點可靠性之外需要考慮的另一個可靠性問題。

參考資料:

1.百度百科
2.http://en.wikipedia.org/wiki/Java_Transaction_API
3.http://www.nosqlnotes.NET/archives/62#more-62
4.http://hi.baidu.com/javaopensource/blog/item/0a2b764ec501b10cb3de05ba.html

 

-------------------------------------其他----------------------------------

一、二階段提交算法描述  
  在分布式系統中,事務往往包含有多個參與者的活動,單個參與者上的活動是能夠保證原子性的,而多個參與者之間原子性的保證則需要通過兩階段提交來實現,兩階段提交是分布式事務實現的關鍵。

  很明顯,兩階段提交保證了分布式事務的原子性,這些子事務要么都做,要么都不做。而數據庫的一致性是由數據庫的完整性約束實現的,持久性則是通過commit日志來實現的,不是由兩階段提交來保證的。至於兩階段提交如何保證隔離性,可以參考Large-scale Incremental Processing Using Distributed Transactions and Notifications中兩階段提交的具體實現。

  兩階段提交的過程涉及到協調者和參與者。協調者可以看做成事務的發起者,同時也是事務的一個參與者。對於一個分布式事務來說,一個事務是涉及到多個參與者的。具體的兩階段提交的過程如下: 
第一階段: 
  首先,協調者在自身節點的日志中寫入一條的日志記錄,然后所有參與者發送消息prepare T,詢問這些參與者(包括自身),是否能夠提交這個事務; 
  參與者在接受到這個prepare T 消息以后,會根據自身的情況,進行事務的預處理,如果參與者能夠提交該事務,則會將日志寫入磁盤,並返回給協調者一個ready T信息,同時自身進入可提交狀態;如果不能提交該事務,則記錄日志,並返回一個not commit T信息給協調者,同時撤銷在自身上所做的數據庫改; 
第二階段: 
  協調者會收集所有參與者的意見。(1)如果收到參與者發來的not commit T信息,則標識着該事務不能提交,協調者會將Abort T 記錄到日志中,並向所有參與者發送一個Abort T 信息,讓所有參與者撤銷在自身上所有的預操作;(2)如果協調者收到所有參與者發來prepare T信息,那么協調者會將Commit T日志寫入磁盤,並向所有參與者發送一個Commit T信息,提交該事務。(3)若協調者遲遲未收到某個參與者發來的信息,則認為該參與者發送了一個VOTE_ABORT信息,從而取消該事務的執行。 
  參與者接收到協調者發來的Abort T信息以后,參與者會終止提交,並將Abort T 記錄到日志中;如果參與者收到的是Commit T信息,則會將事務進行提交,並寫入記錄。

二、可能出現的問題 
  一般情況下,兩階段提交機制都能較好的運行,但可能出現下面三種問題: 
  (1)協調者不宕機,參與者宕機; 
  (2)協調者宕機,參與者不宕機; 
  (3)協調者宕機,參與者也宕機; 
  對於(1),當在事務進行過程中,有參與者宕機時,他重啟以后,可以通過詢問其他參與者或者協調者,從而知道這個事務到底提交了沒有。當然,這一切的前提都是各個參與者在進行每一步操作時,都會事先寫入日志。 
  對於(2),協調者宕機后,可以起新的協調者,然后查詢所有參與者的狀態是否有commit的,如果有,則繼續commit,如果都沒有,則abort。 
  對於(3),是唯一一個兩階段提交不能解決的困境是:當協調者在發出commit T消息后宕機了,而唯一收到這條命令的一個參與者也宕機了,這個時候這個事務就處於一個未知的狀態,沒有人知道這個事務到底是提交了還是未提交,從而需要數據庫管理員的介入,防止數據庫進入一個不一致的狀態。當然,如果有一個前提是:所有節點或者網絡的異常最終都會恢復,那么這個問題就不存在了,協調者和參與者最終會重啟,其他節點也最終也會收到commit T的信息。 
  對於上面的困境,業界提出了三階段提交的方法來此問題,即將二階段提交的第二階段再分為待定階段(或預提交階段)和確定階段,從而變為三階段;在待定階段協調者log prepare_commit消息后向所有參與者發送prepare_commit消息, 待收到所有參與者回包(這里的回包結果只會成功)或超時時就進入第三段階,log commit消息並向所有參與者發送commit消息。如果在待定階段和確定階段出現協調者和部分參與者同時宕機(即上面的困境),只要存活的協調者或參與者里有prepare_commit或commit消息,新的協調者可以繼續進行commit消息,如果沒有,就不commit消息,從而保證數據的一致性。

3 日志 
數據庫日志保證了事務執行的原子性和持久性,日志類型可以分為redo log,undo log,undo/redo log。

4 總結 
二階段提交和三階段提交都是很好的分布式事務算法,三階段提交是為解決二階段提交未解決的問題(協調者宕機,參與者也宕機)而提出來的。不過這兩種算法都只考慮一個協調者(主節點)的情況,沒有考慮多個協調者和如何選出協調者的問題。而另一種知名分布式事務算法Paxos能解決多個協調者的情況,並提出了多數派的概念。


免責聲明!

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



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