MySQL分佈式事務(XA事務) html
官網: https://dev.mysql.com/doc/refman/5.7/en/xa.html
java
分佈式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位於不一樣的分佈式系統的不一樣節點之上。以上是百度百科的解釋,簡單的說,就是一次大的操做由不一樣的小操做組成,這些小的操做分佈在不一樣的服務器上,且屬於不一樣的應用,分佈式事務須要保證這些小操做要麼所有成功,要麼所有失敗。本質上來講,分佈式事務就是爲了保證不一樣數據庫的數據一致性。 mysql
當數據庫單表一年產生的數據超過1000W,那麼就要考慮分庫分表,具體分庫分表的原理在此不作解釋,之後有空詳細說,簡單的說就是原來的一個數據庫變成了多個數據庫。這時候,若是一個操做既訪問01庫,又訪問02庫,並且要保證數據的一致性,那麼就要用到分佈式事務。 linux
所謂的SOA化,就是業務的服務化。好比原來單機支撐了整個電商網站,如今對整個網站進行拆解,分離出了訂單中心、用戶中心、庫存中心。對於訂單中心,有專門的數據庫存儲訂單信息,用戶中心也有專門的數據庫存儲用戶信息,庫存中心也會有專門的數據庫存儲庫存信息。這時候若是要同時對訂單和庫存進行操做,那麼就會涉及到訂單數據庫和庫存數據庫,爲了保證數據一致性,就須要用到分佈式事務。 git
以上兩種狀況表象不一樣,可是本質相同,都是由於要操做的數據庫變多了! github
所謂的原子性就是說,在整個事務中的全部操做,要麼所有完成,要麼所有不作,沒有中間狀態。對於事務在執行中發生錯誤,全部的操做都會被回滾,整個事務就像從沒被執行過同樣。 面試
事務的執行必須保證系統的一致性,就拿轉帳爲例,A有500元,B有300元,若是在一個事務裏A成功轉給B50元,那麼無論併發多少,無論發生什麼,只要事務執行成功了,那麼最後A帳戶必定是450元,B帳戶必定是350元。 redis
所謂的隔離性就是說,事務與事務之間不會互相影響,一個事務的中間狀態不會被其餘事務感知。 算法
所謂的持久性,就是說一單事務完成了,那麼事務對數據所作的變動就徹底保存在了數據庫中,即便發生停電,系統宕機也是如此。 sql
最經典的場景就是支付了,一筆支付,是對買家帳戶進行扣款,同時對賣家帳戶進行加錢,這些操做必須在一個事務裏執行,要麼所有成功,要麼所有失敗。而對於買家帳戶屬於買家中心,對應的是買家數據庫,而賣家帳戶屬於賣家中心,對應的是賣家數據庫,對不一樣數據庫的操做必然須要引入分佈式事務。
買家在電商平臺下單,每每會涉及到兩個動做,一個是扣庫存,第二個是更新訂單狀態,庫存和訂單通常屬於不一樣的數據庫,須要使用分佈式事務保證數據一致性。
XA是一個分佈式事務協議,由Tuxedo提出。XA中大體分爲兩部分:事務管理器和本地資源管理器。其中本地資源管理器每每由數據庫實現,好比Oracle、DB2這些商業數據庫都實現了XA接口,而事務管理器做爲全局的調度者,負責各個本地資源的提交和回滾。XA實現分佈式事務的原理以下:
總的來講,XA協議比較簡單,並且一旦商業數據庫實現了XA協議,使用分佈式事務的成本也比較低。可是,XA也有致命的缺點,那就是性能不理想,特別是在交易下單鏈路,每每併發量很高,XA沒法知足高併發場景。XA目前在商業數據庫支持的比較理想,在mysql數據庫中支持的不太理想,mysql的XA實現,沒有記錄prepare階段日誌,主備切換回致使主庫與備庫數據不一致。許多nosql也沒有支持XA,這讓XA的應用場景變得很是狹隘。
XA事務就是兩階段提交的一種實現方式
XA規範主要定義了事務管理器TM,和資源管理器RM之間的接口
根據2PC的規範,將一次事務分割成兩個階段
1. prepare階段
TM向全部RM發送prepare指令,RM接受到指令後執行數據修改和日誌記錄等操做,而後返回 能夠提交/不可提交 給TM
(按照個人理解應該相似於MySQL在開啓一個事務以後,只差最後的COMMIT或者ROLLBACK的狀態)
2. commit階段
TM接受到全部RM的prepare結果
若是有RM返回是 不可提交 或者超時,那麼向全部RM發送ROLLBACK命令
若是全部RM都返回能夠提交,那麼向全部RM發送COMMIT命令
XA的異常狀況處理
MySQL與XA事務的關係有兩種狀況
1. 內部XA
在使用innodb做爲存儲引擎,而且開啓binlog的狀況下,MySQL同時維護了binlog日誌與innodb的redo log
爲了保證這兩個日誌的一致性,MySQL使用了XA事務,因爲只在單機上工做,因此被稱爲內部XA
2. 外部XA
就是通常談論的分佈式事務了
MySQL支持XA START/END/PREPARE/COMMIT這些sql語句,經過使用這些命令,咱們是能夠完成分佈式事務的
狀態轉移圖以下
(我有點不能理解的是,爲何必定須要XA END這個語句,直接XA PREPARE不行嗎)
在MySQL5.7.7以前,XA事務是有bug的
若是有一個XA事務處於PREPARE狀態
1. 若是鏈接關閉,或者MySQL服務器正常退出,這個事務會被回滾(可是根據XA規範,這個事務應該被保留)
2. 若是MySQL服務器被強制結束,在重啓以後,用XA RECOVER命令能夠看到這個事務,這個事務也能夠被XA COMMIT所提交,可是相關的binlog記錄會丟失,這樣就會致使數據庫引擎中的數據與binlog中的數據不一致 (參考資料)
這兩個bug被提出了十年之久,終於在5.7.7中被修正了(第一個bug阿里本身也搞了個修正)
就目前來看,MySQL的XA事務如今作得還不錯,應該是可用的
仍是有一些不能理解的地方
1. 官方文檔中強調:在使用分佈式事務的時候,須要使用串行隔離級別,爲何?
(As with nondistributed transactions, SERIALIZABLE may be preferred if your applications are sensitive to read phenomena. REPEATABLE READ may not be sufficient for distributed transactions.)
緣由:爲了儘量提升分佈式事物的隔離級別,若是分庫上使用MySQL默認的RR,那麼致使總的分佈式事務的隔離級別爲RU
參考資料
1. MySQL binlog 組提交與 XA(兩階段提交)
2. MySQL redolog與組提交 資料1 資料2 資料3 資料4
3. MySQL官方的XA文檔
4. XA事務的隔離級別
普通事務的實現是比較好理解的。以jdbm3爲例,大概是這樣的過程:
每一個事務都新建一個事務文件,當commit時,先把修改過的數據塊,寫到事務文件裏,而後再一次性地寫到數據庫文件裏。
若是commit時掛掉了,那麼重啓以後,會再次從事務文件裏把修改過的塊寫到數據庫文件裏。最後再刪除事務文件。
https://github.com/jankotek/JDBM3
可是XA事務,即所謂的分佈式事務卻使人感到雲裏霧裏。一是資料不多,網上的各類配置資料都是流於表面;二是可能實際應用的人也少。
最近研究了下,算是找到點門道了。
首先,XA事務是基於二階段提交(Two-phase Commit)實現的。二階段提交自己並無什麼使人疑惑的地方。看wiki就能夠知道是怎麼回事了。
簡而言之,有二種角色,事務管理者(DM, Transaction Manager),資源管理器(RM, Resource Manager),一般即數據庫或者JMS服務器。
下面兩個圖片來自:http://www.infoq.com/cn/articles/xa-transactions-handle
出錯回滾:
固然,還有各類中間出錯時,要處理的狀況,詳細能夠看infoq的原文。
二階段提交協議是很容易理解的,可是真正令我疑惑的是Java實現的atomikos,一個分佈式事務的Transaction Manager組件。
開始的時候,我覺得事務管理器(TM)都是獨立的一個服務,或者一個獨立的進程,它和資源管理器(RM)之間經過網絡通迅。
可是在網上看一些atomikos配置文章,都沒有提到如何配置一個獨立的Transaction Manager,只是簡單地介紹了下如何配置atomikos,這些配置都是和應用在一塊兒的。
而從配置裏面也無法看出是如何保證在事務過程當中,若是應用的進程掛掉後,是如何恢復的。
再把atomikos的例子代碼下載下來,發現也沒有提到是如何保證事務在失敗後,如何協調的。
好比,在第二段提交時,當RM1 commit完成了,而RM2 commit尚未完成,而這時TM,即配置了atomikos的應用程序崩潰,那麼這個事務並無完成,還須要TM重啓後協調,才能最終完成這個事務。可是沒看到恢復部分的配置。
沒辦法,只能親自跑一遍代碼了。
跑了下atomikos的代碼,在第二階段提交時,把進程殺掉,發現的確是能夠自動處理回滾事務,或者再次提交的。那麼信息是保存在哪裏的?也沒有看到有什麼配置文件。
最終,只能下XA的規範下載下來,再一點點慢慢看。
在The XA Specification裏的2.3小節:Transaction Completion and Recovery 明確提到TM是要記錄日誌的:
In Phase 2, the TM issues all RMs an actual request to commit or roll back the
transaction branch, as the case may be. (Before issuing requests to commit, the TM
stably records the fact that it decided to commit, as well as a list of all involved RMs.)
All RMs commit or roll back changes to shared resources and then return status to the
TM. The TM can then discard its knowledge of the global transaction.
TM是必定要把事務的信息,好比XID,哪一個RM已經完成了等保存起來的。只有當所有的RM提交或者回滾完後,才能丟棄這些事務的信息。
因而再查看下atomikos例子運行目錄,果真有一些文件日誌文件:
127.0.1.1.tm13.epoch
tmlog13.log
tmlog.lck
tm.out
tm.out.lck
原來atomikos是經過在應用的目錄下生成日誌文件來保證,若是失敗,在重啓後能夠經過日誌來完成未完成的事務。
從XA的規範裏找到了下面的說法:
The X/Open DTP model makes these assumptions:
TMs and RMs have access to stable storage TM和RM都有牢靠的存儲
TMs coordinate and control recovery TM協調和控制恢復流程
RMs provide for their own restart and recovery of their own state. On request, an RM must give a TM a list of XIDs that the RM has prepared for commitment or has heuristically completed. RM在得啓和恢復時,得迴應TM的請求,返回一系列的XID,是prepared的,或者是已經啓發式地完成了的
也就是說,XA事務都假定了TM和RM都是有牢靠的存儲的,因此也保證了TM重啓後能夠從日誌裏恢復還沒處理完的事務。
TM能夠向RM查詢事務的狀態,RM必需要返回一系列事務的XID,代表事務是prepared狀態,仍是已經commit的狀態。
到這裏,應該很明瞭了,XA事務是其限制的,而TM是XA事務的一個單點,TM必需要很是地牢靠。
從XA的接口函數,就能夠大概看出協議是怎麼工做的(來自XA規範文檔):
XA事務的明顯問題是timeout問題,好比當一個RM出問題了,那麼整個事務只能處於等待狀態。這樣能夠會連鎖反應,致使整個系統都很慢,最終不可用。
避免使用XA事務的方法一般是最終一致性。
舉個例子,好比用戶充值300元,爲了減小DB的壓力,先把這個放到消息隊列裏,而後後端再從消息隊列裏取出消息,更新DB。
那麼如何保證,這條消息不會被重複消費?或者重複消費後,仍能保證結果是正確的?
前面兩種方法都必須從流程上保證是單方向的,不能插入其它的東東。
貌似一直有人想用zookeeper來實現2pc,或者相似的東東,由於zookeeper是比較可靠的。可是感受也沒有辦法解決timeout問題。
微軟的XA事務恢復流程的文檔:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681775(v=vs.85).aspx
There are two forms of XA transaction recovery, as follows:
XA事務沒有什麼神祕的地方,二階段提交也是一我的們很天然的一個處理方式。
只不過,這個是規範,若是有多個資源之間要協調,並且都支持XA事務,那麼會比較方便 。
The XA Specification 能夠從這裏下載到:http://download.csdn.NET/detail/hengyunabc/6940529
http://en.wikipedia.org/wiki/Two-phase_commit_protocol
http://www.infoq.com/cn/articles/xa-transactions-handle
http://java.sun.com/javaee/technologies/jta/index.jsp
https://github.com/bitronix/btm 一個開源的JTA Transaction Manager
XA接口是雙向的系統接口,分佈式事務是由一個一個應用程序(Application Program)、一個事務管理器(Transaction Manager)以及一個或多個資源管理器(Resource Manager)之間造成通訊橋樑。事務管理器控制着JTA事務,管理事務生命週期,並協調資源。
在JTA中,事務管理器抽象爲javax.transaction.TransactionManager接口,並經過底層事務服務(即JTS)實現。資源管理器負責控制和管理實際資源(如數據庫或JMS隊列)。下圖說明了事務管理器、資源管理器,以及典型JTA環境中客戶端應用之間的關係:
XA分佈式事務是由一個或者多個Resource Managerd,一個事務管理器Transaction Manager以及一個應用程序 Application Program組成。
資源管理器:提供訪問事務資源的方法,一般一個數據庫就是一個資源管理器。
事務管理器:協調參與全局事務中的各個事務。須要和參與全局事務中的資源管理器進行通訊。
應用程序:定義事務的邊界,指定全局事務中的操做。
許多事務管理器採用這種單階段提交的模式,能夠避免單一事務資源下的過分開銷,以及性能的降低,若是在不適合的場景中引入XA數據庫驅動,特別是資源比較侷限的狀況下使用本地事務模型(Local Transaction Model)。
那究竟什麼狀況下使用XA事務呢?
通常來講,當你的上下邏輯結構涉及的表或者須要協調的資源(如數據庫,以及消息主題或隊列等)比較多的時候,建議使用XA。
或者對於該系統在將來對整個結構模塊趨於穩定,要求負載、代碼擴展等方面穩定性大於性能,則可選擇XA。
若是這些資源並不在同一個事務中使用,就沒有必要去用XA。
而對於性能要求很高的系統,建議使用 一階段提交(Best Efforts 1PC)或事務補償機制。
二階段提交是分佈式事務的重要的一個關鍵點,二階段提交協議包含了兩個階段:第一階段(也稱準備階段)和第二階段(也稱提交階段)。
引用《Java事務設計策略》一圖
1. 準備階段:準備階段,每一個資源管理器都會被輪訓一遍,事務管理器給每一個資源管理器發送Prepare消息,每一個資源管理器要麼直接返回失敗(如權限驗證失敗)或異常,要麼在本地執行事務等等,但不Commoit,處於Ready狀態。
2. 提交階段:若是事務管理器收到了資源管理器的失敗信息(如異常、超時等),直接給每一個資源管理器發送回滾(Rollback)消息;不然,發送提交(Commit)消息;資源管理器根據事務管理器的指令執行Commit或者Rollback操做,釋放全部事務處理過程當中使用的鎖資源。(注意:必須在最後階段釋放鎖資源)
能夠看出,二階段提交這麼作的就是讓前面都完成了準備工做,才能提交整個事務,若中間由某一環節出現問題,則整個事務回滾。
從兩階段提交的工做方式來看,很顯然,在提交事務的過程當中須要在多個節點之間進行協調,而各節點對鎖資源的釋放必須等到事務最終提交時,這樣,比起一階段提交,兩階段提交在執行一樣的事務時會消耗更多時間。事務執行時間的延長意味着鎖資源發生衝突的機率增長,當事務的併發量達到必定數量的時候,就會出現大量事務積壓甚至出現死鎖,系統性能就會嚴重下滑。
二階段提交看起來確實可以提供原子性的操做,可是不幸的事,二階段提交仍是有幾個缺點的:
一、同步阻塞問題。執行過程當中,全部參與節點都是事務阻塞型的。當參與者佔有公共資源時,其餘第三方節點訪問公共資源不得不處於阻塞狀態。
二、單點故障。因爲協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤爲在第二階段,協調者發生故障,那麼全部的參與者還都處於鎖定事務資源的狀態中,而沒法繼續完成事務操做。(若是是協調者掛掉,能夠從新選舉一個協調者,可是沒法解決由於協調者宕機致使的參與者處於阻塞狀態的問題)
三、數據不一致。在二階段提交的階段二中,當協調者向參與者發送commit請求以後,發生了局部網絡異常或者在發送commit請求過程當中協調者發生了故障,這回致使只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求以後就會執行commit操做。可是其餘部分未接到commit請求的機器則沒法執行事務提交。因而整個分佈式系統便出現了數據部一致性的現象。
四、二階段沒法解決的問題:協調者再發出commit消息以後宕機,而惟一接收到這條消息的參與者同時也宕機了。那麼即便協調者經過選舉協議產生了新的協調者,這條事務的狀態也是不肯定的,沒人知道事務是否被已經提交。
參考資料
http://www.infoq.com/cn/articles/xa-transactions-handle
http://blog.csdn.net/bluishglc/article/details/7612811
http://www.open-open.com/lib/view/open1429863503010.html
http://hedengcheng.com/?p=136
http://www.hollischuang.com/archives/681
事務和兩階段提交,三階段提交協議(有限狀態自動機)
?1 事務的ACID
事務是保證數據庫從一個一致性的狀態永久地變成另一個一致性狀態的根本,其中,ACID是事務的基本特性。
A是Atomicity,原子性。一個事務每每涉及到許多的子操做,原子性則保證這些子操做要麼都作,要麼都不作,而不至於出現事務的部分操
做成功,而另一部分操做沒有成功。若是事務在執行的過程當中發生錯誤,那麼數據庫將回滾到事務發生以前的狀態。好比銀行的轉帳服務
,這個事務的最終結果必定是:某個帳戶的餘額增長了x,而另一個帳戶的餘額減小了x,或者兩個帳戶的餘額未發生變化。而不會出現其
他狀況。
C是Consistency,一致性。一致性是指事務發生前和發生之後,都不會破壞數據庫的約束關係,保證了數據庫元素的正確性、有效性和完整
性。這種約束關係能夠是數據庫內部的約束,好比數據庫元素的值必須在必定的範圍內,也能夠是應用帶來的約束,好比轉帳之後銀行帳戶
的餘額不能爲負數。
I是Isolation,隔離性。一個事務的操做在未提交之前,是不會被並行發生的其餘事務訪問到的。也就是說,數據庫操做不會看到某個事務
的中間操做結果,好比轉帳過程當中,用戶是不能查詢到一個帳戶餘額減小了,而另一個帳戶餘額未發生變化的狀況。
D是Durability,持久性。事務完成之後,它對數據庫的影響是永久性的,即便在數據庫系統發生宕機或者其餘故障的狀況下,這種影響也
會獲得保持。
?2 兩階段提交
應用在分佈式系統中。
在分佈式系統中,事務每每包含有多個參與者的活動,單個參與者上的活動是可以保證原子性的,而多個參與者之間原子性的保證則須要通
過兩階段提交來實現,兩階段提交是分佈式事務實現的關鍵。
很明顯,兩階段提交保證了分佈式事務的原子性,這些子事務要麼都作,要麼都不作。而數據庫的一致性是由數據庫的完整性約束實現的,
持久性則是經過commit日誌來實現的,不是由兩階段提交來保證的。至於兩階段提交如何保證隔離性,能夠參考Large-scale Incremental
Processing Using Distributed Transactions and Notifications中兩階段提交的具體實現。
兩階段提交的過程涉及到協調者和參與者。協調者能夠看作成事務的發起者,同時也是事務的一個參與者。對於一個分佈式事務來講,一個
事務是涉及到多個參與者的。具體的兩階段提交的過程以下:
第一階段:
首先,協調者在自身節點的日誌中寫入一條的日誌記錄,而後全部參與者發送消息prepare T,詢問這些參與者(包括自身),是否可以提
交這個事務;
參與者在接受到這個prepare T 消息之後,會根據自身的狀況,進行事務的預處理,若是參與者可以提交該事務,則會將日誌寫入磁盤,並
返回給協調者一個ready T信息,同時自身進入預提交狀態狀態;若是不能提交該事務,則記錄日誌,並返回一個not commit T信息給協調
者,同時撤銷在自身上所作的數據庫改;
參與者可以推遲發送響應的時間,但最終仍是須要發送的。
第二階段:
協調者會收集全部參與者的意見,若是收到參與者發來的not commit T信息,則標識着該事務不能提交,協調者會將Abort T 記錄到日誌中
,並向全部參與者發送一個Abort T 信息,讓全部參與者撤銷在自身上全部的預操做;
若是協調者收到全部參與者發來prepare T信息,那麼協調者會將Commit T日誌寫入磁盤,並向全部參與者發送一個Commit T信息,提交該
事務。若協調者遲遲未收到某個參與者發來的信息,則認爲該參與者發送了一個VOTE_ABORT信息,從而取消該事務的執行。
參與者接收到協調者發來的Abort T信息之後,參與者會終止提交,並將Abort T 記錄到日誌中;若是參與者收到的是Commit T信息,則會
將事務進行提交,並寫入記錄
通常狀況下,兩階段提交機制都能較好的運行,當在事務進行過程當中,有參與者宕機時,他重啓之後,能夠經過詢問其餘參與者或者協調者
,從而知道這個事務到底提交了沒有。固然,這一切的前提都是各個參與者在進行每一步操做時,都會事先寫入日誌。
惟一一個兩階段提交不能解決的困境是:當協調者在發出commit T消息後宕機了,而惟一收到這條命令的一個參與者也宕機了,這個時候這
個事務就處於一個未知的狀態,沒有人知道這個事務究竟是提交了仍是未提交,從而須要數據庫管理員的介入,防止數據庫進入一個不一致
的狀態。固然,若是有一個前提是:全部節點或者網絡的異常最終都會恢復,那麼這個問題就不存在了,協調者和參與者最終會重啓,其餘
節點也最終也會收到commit T的信息。
?3 日誌
數據庫日誌保證了事務執行的原子性和持久性,日誌類型能夠分爲redo log,undo log,undo/redo log。關於這幾種日誌形式的具體介紹
,能夠參照:
http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog
--------------------\
兩階段提交協議(two phase commit protocol,2PC)能夠保證數據的強一致性,許多分佈式關係型數據管理系統採用此協議來完成分佈式
事務。它是協調全部分佈式原子事務參與者,並決定提交或取消(回滾)的分佈式算法。同時也是解決一致性問題的一致性算法。該算法能
夠解決不少的臨時性系統故障(包括進程、網絡節點、通訊等故障),被普遍地使用。可是,它並不可以經過配置來解決全部的故障,在某
些狀況下它還須要人爲的參與才能解決問題。參與者爲了可以從故障中恢復,它們都使用日誌來記錄協議的狀態,雖然使用日誌下降了性能
可是節點可以從故障中恢復。
在兩階段提交協議中,系統通常包含兩類機器(或節點):一類爲協調者(coordinator),一般一個系統中只有一個;另外一類爲事務參與
者(participants,cohorts或workers),通常包含多個,在數據存儲系統中能夠理解爲數據副本的個數。協議中假設每一個節點都會記錄寫
前日誌(write-ahead log)並持久性存儲,即便節點發生故障日誌也不會丟失。協議中同時假設節點不會發生永久性故障並且任意兩個節
點均可以互相通訊。
當事務的最後一步完成以後,協調器執行協議,參與者根據本地事務可以成功完成回覆贊成提交事務或者回滾事務。
顧名思義,兩階段提交協議由兩個階段組成。在正常的執行下,這兩個階段的執行過程以下所述:
階段1:請求階段(commit-request phase,或稱表決階段,voting phase)
在請求階段,協調者將通知事務參與者準備提交或取消事務,而後進入表決過程。在表決過程當中,參與者將告知協調者本身的決策:贊成(
事務參與者本地做業執行成功)或取消(本地做業執行故障)。
階段2:提交階段(commit phase)
在該階段,協調者將基於第一個階段的投票結果進行決策:提交或取消。當且僅當全部的參與者贊成提交事務協調者才通知全部的參與者提
交事務,不然協調者將通知全部的參與者取消事務。參與者在接收到協調者發來的消息後將執行響應的操做。
注意 兩階段提交協議與兩階段鎖協議不一樣,兩階段鎖協議爲一致性控制協議。
-------------
XA
XA是X/Open DTP組織(X/Open DTP group)定義的兩階段提交協議,XA被許多數據庫(如Oracle和DB2)和中間件等工具(如CICS 和
Tuxedo).本地支持 。
X/Open DTP模型(1994)包括應用程序(AP)、事務管理器(TM)、資源管理器(RM)、通訊資源管理器(CRM)四部分。在這個模型中,
一般事務管理器(TM)是交易中間件,資源管理器(RM)是數據庫,通訊資源管理器(CRM)是消息中間件。
通常狀況下,某一數據庫沒法知道其它數據庫在作什麼,所以,在一個DTP環境中,交易中間件是必需的,由它通知和協調相關數據庫的提
交或回滾。而一個數據庫只將其本身所作的操做(可恢復)影射到全局事務中。
XA就是X/Open DTP定義的交易中間件與數據庫之間的接口規範(即接口函數),交易中間件用它來通知數據庫事務的開始、結束以及提交、
回滾等。XA接口函數由數據庫廠商提供。一般狀況下,交易中間件與數據庫經過XA 接口規範,使用兩階段提交來完成一個全局事務,XA規
範的基礎是兩階段提交協議。
XA–eXtended Architecture 在事務中意爲分佈式事務
XA由協調者(coordinator,通常爲transaction manager)和參與者(participants,通常在各個資源上有各自的resource manager)共同完成。在MySQL中,XA事務有兩種。
內部XA事務
mysql自己的插件式架構致使在其內部須要使用XA事務,此時MySQL便是協調者,也是參與者。例如,不一樣的存儲引擎之間是徹底獨立的,所以當一個事務涉及兩個不一樣的存儲引擎時,就必須使用內部XA事務。須要特別注意的是,若是將二進制日誌看作一個獨立的「存儲引擎」,就不難理解爲何即便是一個存儲引擎參與的事務也須要使用XA事務了。在向存儲引擎提交數據時,同時須要將提交的信息寫入二進制日誌,這就是一個分佈式事務。
下面的SQL就實現了一個簡單的MySQL XA事務:
mysql> XA START 'xatest'; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO mytable (i) VALUES(10); Query OK, 1 row affected (0.04 sec) mysql> XA END 'xatest'; Query OK, 0 rows affected (0.00 sec) mysql> XA PREPARE 'xatest'; Query OK, 0 rows affected (0.00 sec) mysql> XA COMMIT 'xatest'; Query OK, 0 rows affected (0.00 sec)
外部XA事務
MySQL也能夠僅做爲一個外部XA的參與者。例如在Java程序中實現一個操做多個異構數據庫數據的分佈式事務,則分工爲:
Transaction Manager
javax.transaction.xa.XAResource, or Java::BitronixTm(aka 「Transaction Coordinator」) 也就是程序自己
Resource Managers
MySQL, PostgreSQL, Oracle, Redis, MQueue, MongoDB, etc.(aka 「cohorts」) 即各個數據庫。也就是說只要是提供了相應接口的數據庫產品就能夠做爲XA的參與者
Two-phase commit
XA通常由兩階段完成,稱爲two-phase commit(2PC)。
階段一爲準備階段,即全部的參與者準備執行事務並鎖住須要的資源。參與者ready時,向transaction manager彙報本身已經準備好。
階段二爲提交階段。當transaction manager確認全部參與者都ready後,向全部參與者發送commit命令。
以下圖所示:
XA的性能問題
XA的性能很低。一個數據庫的事務和多個數據庫間的XA事務性能對比可發現,性能差10倍左右。所以要儘可能避免XA事務,例如能夠將數據寫入本地,用高性能的消息系統分發數據。或使用數據庫複製等技術。
只有在這些都沒法實現,且性能不是瓶頸時才應該使用XA。
最後是MySQL的XA官方文檔:
http://dev.mysql.com/doc/refman/5.7/en/xa.html
在開發中,爲了下降單點壓力,一般會根據業務狀況進行分表分庫,將表分佈在不一樣的庫中(庫可能分佈在不一樣的機器上)。在這種場景下,事務的提交會變得相對複雜,由於多個節點(庫)的存在,可能存在部分節點提交失敗的狀況,即事務的ACID特性須要在各個不一樣的數據庫實例中保證。好比更新db1庫的A表時,必須同步更新db2庫的B表,兩個更新造成一個事務,要麼都成功,要麼都失敗。
那麼咱們如何利用mysql實現分佈式數據庫的事務呢?
Mysql 爲咱們提供了分佈式事務解決方案(https://dev.mysql.com/doc/refman/5.7/en/xa.html 這是mysql5.7的文檔)
這裏先聲明兩個概念:
mysql在執行分佈式事務(外部XA)的時候,mysql服務器至關於xa事務資源管理器,與mysql連接的客戶端至關於事務管理器。
分佈式事務一般採用2PC協議,全稱Two Phase Commitment Protocol。該協議主要爲了解決在分佈式數據庫場景下,全部節點間數據一致性的問題。分佈式事務經過2PC協議將提交分紅兩個階段:
階段一爲準備(prepare)階段。即全部的參與者準備執行事務並鎖住須要的資源。參與者ready時,向transaction manager報告已準備就緒。
階段二爲提交階段(commit)。當transaction manager確認全部參與者都ready後,向全部參與者發送commit命令。
以下圖所示:
由於XA 事務是基於兩階段提交協議的,因此須要有一個事務協調者(transaction manager)來保證全部的事務參與者都完成了準備工做(第一階段)。若是事務協調者(transaction manager)收到全部參與者都準備好的消息,就會通知全部的事務均可以提交了(第二階段)。MySQL 在這個XA事務中扮演的是參與者的角色,而不是事務協調者(transaction manager)。
XA {START|BEGIN} xid [JOIN|RESUME] 啓動xid事務 (xid 必須是一個惟一值; 不支持[JOIN|RESUME]子句)
XA END xid [SUSPEND [FOR MIGRATE]] 結束xid事務 ( 不支持[SUSPEND [FOR MIGRATE]] 子句)
XA PREPARE xid 準備、預提交xid事務
XA COMMIT xid [ONE PHASE] 提交xid事務
XA ROLLBACK xid 回滾xid事務
XA RECOVER 查看處於PREPARE 階段的全部事務
一、首先要確保mysql開啓XA事務支持
SHOW VARIABLES LIKE '%xa%'
若是innodb_support_xa的值是ON就說明mysql已經開啓對XA事務的支持了。
若是不是就執行:
SET innodb_support_xa = ON
開啓
二、代碼以下:
<!--?PHP $dbtest1 = new mysqli("172.20.101.17","public","public","dbtest1")or die("dbtest1 鏈接失敗"); $dbtest2 = new mysqli("172.20.101.18","public","public","dbtest2")or die("dbtest2 鏈接失敗"); //爲XA事務指定一個id,xid 必須是一個惟一值。 $xid = uniqid(""); //兩個庫指定同一個事務id,代表這兩個庫的操做處於同一事務中 $dbtest1->query("XA START '$xid'");//準備事務1 $dbtest2->query("XA START '$xid'");//準備事務2 try { //$dbtest1 $return = $dbtest1->query("UPDATE member SET name='唐大麥' WHERE id=1") ; if($return == false) { throw new Exception("庫dbtest1@172.20.101.17執行update member操做失敗!"); } //$dbtest2 $return = $dbtest2->query("UPDATE memberpoints SET point=point+10 WHERE memberid=1") ; if($return == false) { throw new Exception("庫dbtest1@172.20.101.18執行update memberpoints操做失敗!"); } //階段1:$dbtest1提交準備就緒 $dbtest1->query("XA END '$xid'"); $dbtest1->query("XA PREPARE '$xid'"); //階段1:$dbtest2提交準備就緒 $dbtest2->query("XA END '$xid'"); $dbtest2->query("XA PREPARE '$xid'"); //階段2:提交兩個庫 $dbtest1->query("XA COMMIT '$xid'"); $dbtest2->query("XA COMMIT '$xid'"); } catch (Exception $e) { //階段2:回滾 $dbtest1->query("XA ROLLBACK '$xid'"); $dbtest2->query("XA ROLLBACK '$xid'"); die($e->getMessage()); } $dbtest1->close(); $dbtest2->close(); ?>
XA的性能很低。一個數據庫的事務和多個數據庫間的XA事務性能對比可發現,性能差10倍左右。所以要儘可能避免XA事務,例如能夠將數據寫入本地,用高性能的消息系統分發數據。或使用數據庫複製等技術。只有在這些都沒法實現,且性能不是瓶頸時才應該使用XA。
About Me
.............................................................................................................................................
● 本文整理自網絡
● 本文在itpub(http://blog.itpub.net/26736162/abstract/1/)、博客園(http://www.cnblogs.com/lhrbest)和我的微信公衆號(xiaomaimiaolhr)上有同步更新
● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/
● 本文博客園地址:http://www.cnblogs.com/lhrbest
● 本文pdf版、我的簡介及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/
● 數據庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/
● DBA寶典今日頭條號地址:http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826
.............................................................................................................................................
● QQ羣號:230161599(滿)、618766405
● 微信羣:可加我微信,我拉你們進羣,非誠勿擾
● 聯繫我請加QQ好友(646634621),註明添加原因
● 於 2017-08-01 09:00 ~ 2017-08-31 22:00 在魔都完成
● 文章內容來源於小麥苗的學習筆記,部分整理自網絡,如有侵權或不當之處還請諒解
● 版權全部,歡迎分享本文,轉載請保留出處
.............................................................................................................................................
● 小麥苗的微店:https://weidian.com/s/793741433?wfr=c&ifr=shopdetail
● 小麥苗出版的數據庫類叢書:http://blog.itpub.net/26736162/viewspace-2142121/
.............................................................................................................................................
使用微信客戶端掃描下面的二維碼來關注小麥苗的微信公衆號(xiaomaimiaolhr)及QQ羣(DBA寶典),學習最實用的數據庫技術。
小麥苗的微信公衆號 小麥苗的DBA寶典QQ羣1 小麥苗的DBA寶典QQ羣2 小麥苗的微店
.............................................................................................................................................
![]()
來自 「 ITPUB博客 」 ,連接:http://blog.itpub.net/26736162/viewspace-2144135/,如需轉載,請註明出處,不然將追究法律責任。