轉(zhuǎn)載:https://yq.aliyun.com/articles/283392
1、什么是分布式事務(wù)
分布式事務(wù)就是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器分別位于不同的分布式系統(tǒng)的不同節(jié)點(diǎn)之上。以上是百度百科的解釋,簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分布在不同的服務(wù)器上,且屬于不同的應(yīng)用,分布式事務(wù)需要保證這些小操作要么全部成功,要么全部失敗。本質(zhì)上來說,分布式事務(wù)就是為了保證不同數(shù)據(jù)庫的數(shù)據(jù)一致性。
2、分布式事務(wù)的產(chǎn)生的原因
2.1、數(shù)據(jù)庫分庫分表
當(dāng)數(shù)據(jù)庫單表一年產(chǎn)生的數(shù)據(jù)超過1000W,那么就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以后有空詳細(xì)說,簡單的說就是原來的一個(gè)數(shù)據(jù)庫變成了多個(gè)數(shù)據(jù)庫。這時(shí)候,如果一個(gè)操作既訪問01庫,又訪問02庫,而且要保證數(shù)據(jù)的一致性,那么就要用到分布式事務(wù)。

2.2、應(yīng)用SOA化
所謂的SOA化,就是業(yè)務(wù)的服務(wù)化。比如原來單機(jī)支撐了整個(gè)電商網(wǎng)站,現(xiàn)在對(duì)整個(gè)網(wǎng)站進(jìn)行拆解,分離出了訂單中心、用戶中心、庫存中心。對(duì)于訂單中心,有專門的數(shù)據(jù)庫存儲(chǔ)訂單信息,用戶中心也有專門的數(shù)據(jù)庫存儲(chǔ)用戶信息,庫存中心也會(huì)有專門的數(shù)據(jù)庫存儲(chǔ)庫存信息。這時(shí)候如果要同時(shí)對(duì)訂單和庫存進(jìn)行操作,那么就會(huì)涉及到訂單數(shù)據(jù)庫和庫存數(shù)據(jù)庫,為了保證數(shù)據(jù)一致性,就需要用到分布式事務(wù)。

以上兩種情況表象不同,但是本質(zhì)相同,都是因?yàn)橐僮鞯臄?shù)據(jù)庫變多了!
3、事務(wù)的ACID特性
3.1、原子性(A)
所謂的原子性就是說,在整個(gè)事務(wù)中的所有操作,要么全部完成,要么全部不做,沒有中間狀態(tài)。對(duì)于事務(wù)在執(zhí)行中發(fā)生錯(cuò)誤,所有的操作都會(huì)被回滾,整個(gè)事務(wù)就像從沒被執(zhí)行過一樣。
3.2、一致性(C)
事務(wù)的執(zhí)行必須保證系統(tǒng)的一致性,就拿轉(zhuǎn)賬為例,A有500元,B有300元,如果在一個(gè)事務(wù)里A成功轉(zhuǎn)給B50元,那么不管并發(fā)多少,不管發(fā)生什么,只要事務(wù)執(zhí)行成功了,那么最后A賬戶一定是450元,B賬戶一定是350元。
3.3、隔離性(I)
所謂的隔離性就是說,事務(wù)與事務(wù)之間不會(huì)互相影響,一個(gè)事務(wù)的中間狀態(tài)不會(huì)被其他事務(wù)感知。
3.4、持久性(D)
所謂的持久性,就是說一單事務(wù)完成了,那么事務(wù)對(duì)數(shù)據(jù)所做的變更就完全保存在了數(shù)據(jù)庫中,即使發(fā)生停電,系統(tǒng)宕機(jī)也是如此。
4、分布式事務(wù)的應(yīng)用場景
4.1、支付
最經(jīng)典的場景就是支付了,一筆支付,是對(duì)買家賬戶進(jìn)行扣款,同時(shí)對(duì)賣家賬戶進(jìn)行加錢,這些操作必須在一個(gè)事務(wù)里執(zhí)行,要么全部成功,要么全部失敗。而對(duì)于買家賬戶屬于買家中心,對(duì)應(yīng)的是買家數(shù)據(jù)庫,而賣家賬戶屬于賣家中心,對(duì)應(yīng)的是賣家數(shù)據(jù)庫,對(duì)不同數(shù)據(jù)庫的操作必然需要引入分布式事務(wù)。
4.2、在線下單
買家在電商平臺(tái)下單,往往會(huì)涉及到兩個(gè)動(dòng)作,一個(gè)是扣庫存,第二個(gè)是更新訂單狀態(tài),庫存和訂單一般屬于不同的數(shù)據(jù)庫,需要使用分布式事務(wù)保證數(shù)據(jù)一致性。
5、常見的分布式事務(wù)解決方案
5.1、基于XA協(xié)議的兩階段提交
XA是一個(gè)分布式事務(wù)協(xié)議,由Tuxedo提出。XA中大致分為兩部分:事務(wù)管理器和本地資源管理器。其中本地資源管理器往往由數(shù)據(jù)庫實(shí)現(xiàn),比如Oracle、DB2這些商業(yè)數(shù)據(jù)庫都實(shí)現(xiàn)了XA接口,而事務(wù)管理器作為全局的調(diào)度者,負(fù)責(zé)各個(gè)本地資源的提交和回滾。XA實(shí)現(xiàn)分布式事務(wù)的原理如下:

總的來說,XA協(xié)議比較簡單,而且一旦商業(yè)數(shù)據(jù)庫實(shí)現(xiàn)了XA協(xié)議,使用分布式事務(wù)的成本也比較低。但是,XA也有致命的缺點(diǎn),那就是性能不理想,特別是在交易下單鏈路,往往并發(fā)量很高,XA無法滿足高并發(fā)場景。XA目前在商業(yè)數(shù)據(jù)庫支持的比較理想,在mysql數(shù)據(jù)庫中支持的不太理想,mysql的XA實(shí)現(xiàn),沒有記錄prepare階段日志,主備切換回導(dǎo)致主庫與備庫數(shù)據(jù)不一致。許多nosql也沒有支持XA,這讓XA的應(yīng)用場景變得非常狹隘。
XA事務(wù)與MySQL
XA事務(wù)就是兩階段提交的一種實(shí)現(xiàn)方式
XA規(guī)范主要定義了事務(wù)管理器TM,和資源管理器RM之間的接口
根據(jù)2PC的規(guī)范,將一次事務(wù)分割成兩個(gè)階段
1. prepare階段
TM向所有RM發(fā)送prepare指令,RM接受到指令后執(zhí)行數(shù)據(jù)修改和日志記錄等操作,然后返回 可以提交/不可提交 給TM
(按照我的理解應(yīng)該類似于MySQL在開啟一個(gè)事務(wù)之后,只差最后的COMMIT或者ROLLBACK的狀態(tài))
2. commit階段
TM接受到所有RM的prepare結(jié)果
如果有RM返回是 不可提交 或者超時(shí),那么向所有RM發(fā)送ROLLBACK命令
如果所有RM都返回可以提交,那么向所有RM發(fā)送COMMIT命令
XA的異常情況處理
MySQL與XA事務(wù)的關(guān)系有兩種情況
1. 內(nèi)部XA
在使用innodb作為存儲(chǔ)引擎,并且開啟binlog的情況下,MySQL同時(shí)維護(hù)了binlog日志與innodb的redo log
為了保證這兩個(gè)日志的一致性,MySQL使用了XA事務(wù),由于只在單機(jī)上工作,所以被稱為內(nèi)部XA
2. 外部XA
就是一般談?wù)摰姆植际绞聞?wù)了
MySQL支持XA START/END/PREPARE/COMMIT這些sql語句,通過使用這些命令,我們是可以完成分布式事務(wù)的
狀態(tài)轉(zhuǎn)移圖如下
(我有點(diǎn)不能理解的是,為什么一定需要XA END這個(gè)語句,直接XA PREPARE不行嗎)
在MySQL5.7.7之前,XA事務(wù)是有bug的
如果有一個(gè)XA事務(wù)處于PREPARE狀態(tài)
1. 如果連接關(guān)閉,或者M(jìn)ySQL服務(wù)器正常退出,這個(gè)事務(wù)會(huì)被回滾(但是根據(jù)XA規(guī)范,這個(gè)事務(wù)應(yīng)該被保留)
2. 如果MySQL服務(wù)器被強(qiáng)制結(jié)束,在重啟之后,用XA RECOVER命令可以看到這個(gè)事務(wù),這個(gè)事務(wù)也可以被XA COMMIT所提交,但是相關(guān)的binlog記錄會(huì)丟失,這樣就會(huì)導(dǎo)致數(shù)據(jù)庫引擎中的數(shù)據(jù)與binlog中的數(shù)據(jù)不一致 (參考資料)
這兩個(gè)bug被提出了十年之久,終于在5.7.7中被修正了(第一個(gè)bug阿里自己也搞了個(gè)修正)
就目前來看,MySQL的XA事務(wù)現(xiàn)在做得還不錯(cuò),應(yīng)該是可用的
還是有一些不能理解的地方
1. 官方文檔中強(qiáng)調(diào):在使用分布式事務(wù)的時(shí)候,需要使用串行隔離級(jí)別,為什么?
(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.)
原因:為了盡可能提高分布式事物的隔離級(jí)別,如果分庫上使用MySQL默認(rèn)的RR,那么導(dǎo)致總的分布式事務(wù)的隔離級(jí)別為RU
參考資料
2. MySQL redolog與組提交 資料1 資料2 資料3 資料4
普通事務(wù)
普通事務(wù)的實(shí)現(xiàn)是比較好理解的。以jdbm3為例,大概是這樣的過程:
每個(gè)事務(wù)都新建一個(gè)事務(wù)文件,當(dāng)commit時(shí),先把修改過的數(shù)據(jù)塊,寫到事務(wù)文件里,然后再一次性地寫到數(shù)據(jù)庫文件里。
如果commit時(shí)掛掉了,那么重啟之后,會(huì)再次從事務(wù)文件里把修改過的塊寫到數(shù)據(jù)庫文件里。最后再刪除事務(wù)文件。
https://github.com/jankotek/JDBM3
但是XA事務(wù),即所謂的分布式事務(wù)卻令人感到云里霧里。一是資料很少,網(wǎng)上的各種配置資料都是流于表面;二是可能實(shí)際應(yīng)用的人也少。
最近研究了下,算是找到點(diǎn)門道了。
二階段提交(Two-phase Commit)
首先,XA事務(wù)是基于二階段提交(Two-phase Commit)實(shí)現(xiàn)的。二階段提交本身并沒有什么令人疑惑的地方。看wiki就可以知道是怎么回事了。
簡而言之,有二種角色,事務(wù)管理者(DM, Transaction Manager),資源管理器(RM, Resource Manager),通常即數(shù)據(jù)庫或者JMS服務(wù)器。
下面兩個(gè)圖片來自:http://www.infoq.com/cn/articles/xa-transactions-handle
[圖片上傳失敗...(image-463692-1585407318380)]
出錯(cuò)回滾:
[圖片上傳失敗...(image-da1992-1585407318380)]
當(dāng)然,還有各種中間出錯(cuò)時(shí),要處理的情況,詳細(xì)可以看infoq的原文。
令人疑惑的atomikos
二階段提交協(xié)議是很容易理解的,但是真正令我疑惑的是Java實(shí)現(xiàn)的atomikos,一個(gè)分布式事務(wù)的Transaction Manager組件。
開始的時(shí)候,我以為事務(wù)管理器(TM)都是獨(dú)立的一個(gè)服務(wù),或者一個(gè)獨(dú)立的進(jìn)程,它和資源管理器(RM)之間通過網(wǎng)絡(luò)通迅。
但是在網(wǎng)上看一些atomikos配置文章,都沒有提到如何配置一個(gè)獨(dú)立的Transaction Manager,只是簡單地介紹了下如何配置atomikos,這些配置都是和應(yīng)用在一起的。
而從配置里面也沒法看出是如何保證在事務(wù)過程中,如果應(yīng)用的進(jìn)程掛掉后,是如何恢復(fù)的。
再把a(bǔ)tomikos的例子代碼下載下來,發(fā)現(xiàn)也沒有提到是如何保證事務(wù)在失敗后,如何協(xié)調(diào)的。
比如,在第二段提交時(shí),當(dāng)RM1 commit完成了,而RM2 commit還沒有完成,而這時(shí)TM,即配置了atomikos的應(yīng)用程序崩潰,那么這個(gè)事務(wù)并沒有完成,還需要TM重啟后協(xié)調(diào),才能最終完成這個(gè)事務(wù)。但是沒看到恢復(fù)部分的配置。
沒辦法,只能親自跑一遍代碼了。
跑了下atomikos的代碼,在第二階段提交時(shí),把進(jìn)程殺掉,發(fā)現(xiàn)的確是可以自動(dòng)處理回滾事務(wù),或者再次提交的。那么信息是保存在哪里的?也沒有看到有什么配置文件。
最終,只能下XA的規(guī)范下載下來,再一點(diǎn)點(diǎn)慢慢看。
在The XA Specification里的2.3小節(jié):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是一定要把事務(wù)的信息,比如XID,哪個(gè)RM已經(jīng)完成了等保存起來的。只有當(dāng)全部的RM提交或者回滾完后,才能丟棄這些事務(wù)的信息。
于是再查看下atomikos例子運(yùn)行目錄,果然有一些文件日志文件:
127.0.1.1.tm13.epoch
tmlog13.log
tmlog.lck
tm.out
tm.out.lck
原來atomikos是通過在應(yīng)用的目錄下生成日志文件來保證,如果失敗,在重啟后可以通過日志來完成未完成的事務(wù)。
XA事務(wù)的假設(shè)條件
從XA的規(guī)范里找到了下面的說法:
The X/Open DTP model makes these assumptions:
TMs and RMs have access to stable storage TM和RM都有牢靠的存儲(chǔ)
TMs coordinate and control recovery TM協(xié)調(diào)和控制恢復(fù)流程
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在得啟和恢復(fù)時(shí),得回應(yīng)TM的請求,返回一系列的XID,是prepared的,或者是已經(jīng)啟發(fā)式地完成了的
也就是說,XA事務(wù)都假定了TM和RM都是有牢靠的存儲(chǔ)的,所以也保證了TM重啟后可以從日志里恢復(fù)還沒處理完的事務(wù)。
TM可以向RM查詢事務(wù)的狀態(tài),RM必須要返回一系列事務(wù)的XID,表明事務(wù)是prepared狀態(tài),還是已經(jīng)commit的狀態(tài)。
到這里,應(yīng)該很明了了,XA事務(wù)是其限制的,而TM是XA事務(wù)的一個(gè)單點(diǎn),TM必須要非常地牢靠。
從XA的接口函數(shù),就可以大概看出協(xié)議是怎么工作的(來自XA規(guī)范文檔):
[圖片上傳失敗...(image-67987f-1585407318379)]
如何避免XA事務(wù)
XA事務(wù)的明顯問題是timeout問題,比如當(dāng)一個(gè)RM出問題了,那么整個(gè)事務(wù)只能處于等待狀態(tài)。這樣可以會(huì)連鎖反應(yīng),導(dǎo)致整個(gè)系統(tǒng)都很慢,最終不可用。
避免使用XA事務(wù)的方法通常是最終一致性。
舉個(gè)例子,比如用戶充值300元,為了減少DB的壓力,先把這個(gè)放到消息隊(duì)列里,然后后端再從消息隊(duì)列里取出消息,更新DB。
那么如何保證,這條消息不會(huì)被重復(fù)消費(fèi)?或者重復(fù)消費(fèi)后,仍能保證結(jié)果是正確的?
- 在消息里帶上用戶帳號(hào)在數(shù)據(jù)庫里的版本,在更新時(shí)比較數(shù)據(jù)的版本,如果相同則加上300;
- 比如用戶本來有500元,那么消息是更新用戶的錢數(shù)為800,而不是加上300;
- 另外建一個(gè)消息是否被消費(fèi)的表,記錄消息ID,在事務(wù)里,先判斷消息是否已經(jīng)消息過,如果沒有,則更新數(shù)據(jù)庫,加上300,否則說明已經(jīng)消費(fèi)過了,丟棄。
前面兩種方法都必須從流程上保證是單方向的,不能插入其它的東東。
其它的一些東東:
貌似一直有人想用zookeeper來實(shí)現(xiàn)2pc,或者類似的東東,因?yàn)閦ookeeper是比較可靠的。但是感覺也沒有辦法解決timeout問題。
微軟的XA事務(wù)恢復(fù)流程的文檔:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681775(v=vs.85).aspx
There are two forms of XA transaction recovery, as follows:
- Cold recovery. Cold recovery performed if the transaction manager process fails while a connection to an XA resource manager is open. When the transaction manager restarts, it reads the transaction manager log file and re-establishes the connection to the XA resource manager by calling xa_open_entry. It then initiates XA recover by calling xa_recover_entry.
- Hot recovery. Hot recovery is performed if the transaction manager remains up while the connection between the transaction manager and the XA resource manager fails because the XA resource manager or the network fails. After the failure, the transaction manager periodically calls xa_open_entry to reconnect to the XA resource manager. When the connection is reestablished, the transaction manager initiates XA recovery by calling xa_recover_entry.
總結(jié):
XA事務(wù)沒有什么神秘的地方,二階段提交也是一個(gè)人們很自然的一個(gè)處理方式。
只不過,這個(gè)是規(guī)范,如果有多個(gè)資源之間要協(xié)調(diào),而且都支持XA事務(wù),那么會(huì)比較方便 。
參考:
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 一個(gè)開源的JTA Transaction Manager
XA接口詳解
XA接口是雙向的系統(tǒng)接口,分布式事務(wù)是由一個(gè)一個(gè)應(yīng)用程序(Application Program)、一個(gè)事務(wù)管理器(Transaction Manager)以及一個(gè)或多個(gè)資源管理器(Resource Manager)之間形成通信橋梁。事務(wù)管理器控制著JTA事務(wù),管理事務(wù)生命周期,并協(xié)調(diào)資源。
在JTA中,事務(wù)管理器抽象為javax.transaction.TransactionManager接口,并通過底層事務(wù)服務(wù)(即JTS)實(shí)現(xiàn)。資源管理器負(fù)責(zé)控制和管理實(shí)際資源(如數(shù)據(jù)庫或JMS隊(duì)列)。下圖說明了事務(wù)管理器、資源管理器,以及典型JTA環(huán)境中客戶端應(yīng)用之間的關(guān)系:

XA分布式事務(wù)是由一個(gè)或者多個(gè)Resource Managerd,一個(gè)事務(wù)管理器Transaction Manager以及一個(gè)應(yīng)用程序 Application Program組成。
資源管理器:提供訪問事務(wù)資源的方法,通常一個(gè)數(shù)據(jù)庫就是一個(gè)資源管理器。
事務(wù)管理器:協(xié)調(diào)參與全局事務(wù)中的各個(gè)事務(wù)。需要和參與全局事務(wù)中的資源管理器進(jìn)行通信。
應(yīng)用程序:定義事務(wù)的邊界,指定全局事務(wù)中的操作。
XA使用場景
許多事務(wù)管理器采用這種單階段提交的模式,可以避免單一事務(wù)資源下的過度開銷,以及性能的下降,如果在不適合的場景中引入XA數(shù)據(jù)庫驅(qū)動(dòng),特別是資源比較局限的情況下使用本地事務(wù)模型(Local Transaction Model)。
那究竟什么情況下使用XA事務(wù)呢?
一般來說,當(dāng)你的上下邏輯結(jié)構(gòu)涉及的表或者需要協(xié)調(diào)的資源(如數(shù)據(jù)庫,以及消息主題或隊(duì)列等)比較多的時(shí)候,建議使用XA。
或者對(duì)于該系統(tǒng)在未來對(duì)整個(gè)結(jié)構(gòu)模塊趨于穩(wěn)定,要求負(fù)載、代碼擴(kuò)展等方面穩(wěn)定性大于性能,則可選擇XA。
如果這些資源并不在同一個(gè)事務(wù)中使用,就沒有必要去用XA。
而對(duì)于性能要求很高的系統(tǒng),建議使用 一階段提交(Best Efforts 1PC)或事務(wù)補(bǔ)償機(jī)制。
二階段提交(The two-phase commit protocol,2PC)
二階段提交是分布式事務(wù)的重要的一個(gè)關(guān)鍵點(diǎn),二階段提交協(xié)議包含了兩個(gè)階段:第一階段(也稱準(zhǔn)備階段)和第二階段(也稱提交階段)。

引用《Java事務(wù)設(shè)計(jì)策略》一圖
1. 準(zhǔn)備階段:準(zhǔn)備階段,每個(gè)資源管理器都會(huì)被輪訓(xùn)一遍,事務(wù)管理器給每個(gè)資源管理器發(fā)送Prepare消息,每個(gè)資源管理器要么直接返回失敗(如權(quán)限驗(yàn)證失敗)或異常,要么在本地執(zhí)行事務(wù)等等,但不Commoit,處于Ready狀態(tài)。
2. 提交階段:如果事務(wù)管理器收到了資源管理器的失敗信息(如異常、超時(shí)等),直接給每個(gè)資源管理器發(fā)送回滾(Rollback)消息;否則,發(fā)送提交(Commit)消息;資源管理器根據(jù)事務(wù)管理器的指令執(zhí)行Commit或者Rollback操作,釋放所有事務(wù)處理過程中使用的鎖資源。(注意:必須在最后階段釋放鎖資源)
可以看出,二階段提交這么做的就是讓前面都完成了準(zhǔn)備工作,才能提交整個(gè)事務(wù),若中間由某一環(huán)節(jié)出現(xiàn)問題,則整個(gè)事務(wù)回滾。
從兩階段提交的工作方式來看,很顯然,在提交事務(wù)的過程中需要在多個(gè)節(jié)點(diǎn)之間進(jìn)行協(xié)調(diào),而各節(jié)點(diǎn)對(duì)鎖資源的釋放必須等到事務(wù)最終提交時(shí),這樣,比起一階段提交,兩階段提交在執(zhí)行同樣的事務(wù)時(shí)會(huì)消耗更多時(shí)間。事務(wù)執(zhí)行時(shí)間的延長意味著鎖資源發(fā)生沖突的概率增加,當(dāng)事務(wù)的并發(fā)量達(dá)到一定數(shù)量的時(shí)候,就會(huì)出現(xiàn)大量事務(wù)積壓甚至出現(xiàn)死鎖,系統(tǒng)性能就會(huì)嚴(yán)重下滑。
二階段提交看起來確實(shí)能夠提供原子性的操作,但是不幸的事,二階段提交還是有幾個(gè)缺點(diǎn)的:
1、同步阻塞問題。執(zhí)行過程中,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的。當(dāng)參與者占有公共資源時(shí),其他第三方節(jié)點(diǎn)訪問公共資源不得不處于阻塞狀態(tài)。
2、單點(diǎn)故障。由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障。參與者會(huì)一直阻塞下去。尤其在第二階段,協(xié)調(diào)者發(fā)生故障,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作。(如果是協(xié)調(diào)者掛掉,可以重新選舉一個(gè)協(xié)調(diào)者,但是無法解決因?yàn)閰f(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問題)
3、數(shù)據(jù)不一致。在二階段提交的階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請求之后,發(fā)生了局部網(wǎng)絡(luò)異?;蛘咴诎l(fā)送commit請求過程中協(xié)調(diào)者發(fā)生了故障,這回導(dǎo)致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之后就會(huì)執(zhí)行commit操作。但是其他部分未接到commit請求的機(jī)器則無法執(zhí)行事務(wù)提交。于是整個(gè)分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象。
4、二階段無法解決的問題:協(xié)調(diào)者再發(fā)出commit消息之后宕機(jī),而唯一接收到這條消息的參與者同時(shí)也宕機(jī)了。那么即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者,這條事務(wù)的狀態(tài)也是不確定的,沒人知道事務(wù)是否被已經(jīng)提交。
參考資料
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
事務(wù)和兩階段提交,三階段提交協(xié)議(有限狀態(tài)自動(dòng)機(jī))
?1 事務(wù)的ACID
事務(wù)是保證數(shù)據(jù)庫從一個(gè)一致性的狀態(tài)永久地變成另外一個(gè)一致性狀態(tài)的根本,其中,ACID是事務(wù)的基本特性。
A是Atomicity,原子性。一個(gè)事務(wù)往往涉及到許多的子操作,原子性則保證這些子操作要么都做,要么都不做,而不至于出現(xiàn)事務(wù)的部分操
作成功,而另外一部分操作沒有成功。如果事務(wù)在執(zhí)行的過程中發(fā)生錯(cuò)誤,那么數(shù)據(jù)庫將回滾到事務(wù)發(fā)生之前的狀態(tài)。比如銀行的轉(zhuǎn)賬服務(wù)
,這個(gè)事務(wù)的最終結(jié)果一定是:某個(gè)賬戶的余額增加了x,而另外一個(gè)賬戶的余額減少了x,或者兩個(gè)賬戶的余額未發(fā)生變化。而不會(huì)出現(xiàn)其
他情況。
C是Consistency,一致性。一致性是指事務(wù)發(fā)生前和發(fā)生以后,都不會(huì)破壞數(shù)據(jù)庫的約束關(guān)系,保證了數(shù)據(jù)庫元素的正確性、有效性和完整
性。這種約束關(guān)系可以是數(shù)據(jù)庫內(nèi)部的約束,比如數(shù)據(jù)庫元素的值必須在一定的范圍內(nèi),也可以是應(yīng)用帶來的約束,比如轉(zhuǎn)賬以后銀行賬戶
的余額不能為負(fù)數(shù)。
I是Isolation,隔離性。一個(gè)事務(wù)的操作在未提交以前,是不會(huì)被并行發(fā)生的其他事務(wù)訪問到的。也就是說,數(shù)據(jù)庫操作不會(huì)看到某個(gè)事務(wù)
的中間操作結(jié)果,比如轉(zhuǎn)賬過程中,用戶是不能查詢到一個(gè)賬戶余額減少了,而另外一個(gè)賬戶余額未發(fā)生變化的情況。
D是Durability,持久性。事務(wù)完成以后,它對(duì)數(shù)據(jù)庫的影響是永久性的,即使在數(shù)據(jù)庫系統(tǒng)發(fā)生宕機(jī)或者其他故障的情況下,這種影響也
會(huì)得到保持。
?2 兩階段提交
應(yīng)用在分布式系統(tǒng)中。
在分布式系統(tǒng)中,事務(wù)往往包含有多個(gè)參與者的活動(dòng),單個(gè)參與者上的活動(dòng)是能夠保證原子性的,而多個(gè)參與者之間原子性的保證則需要通
過兩階段提交來實(shí)現(xiàn),兩階段提交是分布式事務(wù)實(shí)現(xiàn)的關(guān)鍵。
很明顯,兩階段提交保證了分布式事務(wù)的原子性,這些子事務(wù)要么都做,要么都不做。而數(shù)據(jù)庫的一致性是由數(shù)據(jù)庫的完整性約束實(shí)現(xiàn)的,
持久性則是通過commit日志來實(shí)現(xiàn)的,不是由兩階段提交來保證的。至于兩階段提交如何保證隔離性,可以參考Large-scale Incremental
Processing Using Distributed Transactions and Notifications中兩階段提交的具體實(shí)現(xiàn)。
兩階段提交的過程涉及到協(xié)調(diào)者和參與者。協(xié)調(diào)者可以看做成事務(wù)的發(fā)起者,同時(shí)也是事務(wù)的一個(gè)參與者。對(duì)于一個(gè)分布式事務(wù)來說,一個(gè)
事務(wù)是涉及到多個(gè)參與者的。具體的兩階段提交的過程如下:
第一階段:
首先,協(xié)調(diào)者在自身節(jié)點(diǎn)的日志中寫入一條的日志記錄,然后所有參與者發(fā)送消息prepare T,詢問這些參與者(包括自身),是否能夠提
交這個(gè)事務(wù);
參與者在接受到這個(gè)prepare T 消息以后,會(huì)根據(jù)自身的情況,進(jìn)行事務(wù)的預(yù)處理,如果參與者能夠提交該事務(wù),則會(huì)將日志寫入磁盤,并
返回給協(xié)調(diào)者一個(gè)ready T信息,同時(shí)自身進(jìn)入預(yù)提交狀態(tài)狀態(tài);如果不能提交該事務(wù),則記錄日志,并返回一個(gè)not commit T信息給協(xié)調(diào)
者,同時(shí)撤銷在自身上所做的數(shù)據(jù)庫改;
參與者能夠推遲發(fā)送響應(yīng)的時(shí)間,但最終還是需要發(fā)送的。
第二階段:
協(xié)調(diào)者會(huì)收集所有參與者的意見,如果收到參與者發(fā)來的not commit T信息,則標(biāo)識(shí)著該事務(wù)不能提交,協(xié)調(diào)者會(huì)將Abort T 記錄到日志中
,并向所有參與者發(fā)送一個(gè)Abort T 信息,讓所有參與者撤銷在自身上所有的預(yù)操作;
如果協(xié)調(diào)者收到所有參與者發(fā)來prepare T信息,那么協(xié)調(diào)者會(huì)將Commit T日志寫入磁盤,并向所有參與者發(fā)送一個(gè)Commit T信息,提交該
事務(wù)。若協(xié)調(diào)者遲遲未收到某個(gè)參與者發(fā)來的信息,則認(rèn)為該參與者發(fā)送了一個(gè)VOTE_ABORT信息,從而取消該事務(wù)的執(zhí)行。
參與者接收到協(xié)調(diào)者發(fā)來的Abort T信息以后,參與者會(huì)終止提交,并將Abort T 記錄到日志中;如果參與者收到的是Commit T信息,則會(huì)
將事務(wù)進(jìn)行提交,并寫入記錄
一般情況下,兩階段提交機(jī)制都能較好的運(yùn)行,當(dāng)在事務(wù)進(jìn)行過程中,有參與者宕機(jī)時(shí),他重啟以后,可以通過詢問其他參與者或者協(xié)調(diào)者
,從而知道這個(gè)事務(wù)到底提交了沒有。當(dāng)然,這一切的前提都是各個(gè)參與者在進(jìn)行每一步操作時(shí),都會(huì)事先寫入日志。
唯一一個(gè)兩階段提交不能解決的困境是:當(dāng)協(xié)調(diào)者在發(fā)出commit T消息后宕機(jī)了,而唯一收到這條命令的一個(gè)參與者也宕機(jī)了,這個(gè)時(shí)候這
個(gè)事務(wù)就處于一個(gè)未知的狀態(tài),沒有人知道這個(gè)事務(wù)到底是提交了還是未提交,從而需要數(shù)據(jù)庫管理員的介入,防止數(shù)據(jù)庫進(jìn)入一個(gè)不一致
的狀態(tài)。當(dāng)然,如果有一個(gè)前提是:所有節(jié)點(diǎn)或者網(wǎng)絡(luò)的異常最終都會(huì)恢復(fù),那么這個(gè)問題就不存在了,協(xié)調(diào)者和參與者最終會(huì)重啟,其他
節(jié)點(diǎn)也最終也會(huì)收到commit T的信息。
?3 日志
數(shù)據(jù)庫日志保證了事務(wù)執(zhí)行的原子性和持久性,日志類型可以分為redo log,undo log,undo/redo log。關(guān)于這幾種日志形式的具體介紹
,可以參照:
http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog
--------------------
兩階段提交協(xié)議(two phase commit protocol,2PC)可以保證數(shù)據(jù)的強(qiáng)一致性,許多分布式關(guān)系型數(shù)據(jù)管理系統(tǒng)采用此協(xié)議來完成分布式
事務(wù)。它是協(xié)調(diào)所有分布式原子事務(wù)參與者,并決定提交或取消(回滾)的分布式算法。同時(shí)也是解決一致性問題的一致性算法。該算法能
夠解決很多的臨時(shí)性系統(tǒng)故障(包括進(jìn)程、網(wǎng)絡(luò)節(jié)點(diǎn)、通信等故障),被廣泛地使用。但是,它并不能夠通過配置來解決所有的故障,在某
些情況下它還需要人為的參與才能解決問題。參與者為了能夠從故障中恢復(fù),它們都使用日志來記錄協(xié)議的狀態(tài),雖然使用日志降低了性能
但是節(jié)點(diǎn)能夠從故障中恢復(fù)。
在兩階段提交協(xié)議中,系統(tǒng)一般包含兩類機(jī)器(或節(jié)點(diǎn)):一類為協(xié)調(diào)者(coordinator),通常一個(gè)系統(tǒng)中只有一個(gè);另一類為事務(wù)參與
者(participants,cohorts或workers),一般包含多個(gè),在數(shù)據(jù)存儲(chǔ)系統(tǒng)中可以理解為數(shù)據(jù)副本的個(gè)數(shù)。協(xié)議中假設(shè)每個(gè)節(jié)點(diǎn)都會(huì)記錄寫
前日志(write-ahead log)并持久性存儲(chǔ),即使節(jié)點(diǎn)發(fā)生故障日志也不會(huì)丟失。協(xié)議中同時(shí)假設(shè)節(jié)點(diǎn)不會(huì)發(fā)生永久性故障而且任意兩個(gè)節(jié)
點(diǎn)都可以互相通信。
當(dāng)事務(wù)的最后一步完成之后,協(xié)調(diào)器執(zhí)行協(xié)議,參與者根據(jù)本地事務(wù)能夠成功完成回復(fù)同意提交事務(wù)或者回滾事務(wù)。
顧名思義,兩階段提交協(xié)議由兩個(gè)階段組成。在正常的執(zhí)行下,這兩個(gè)階段的執(zhí)行過程如下所述:
階段1:請求階段(commit-request phase,或稱表決階段,voting phase)
在請求階段,協(xié)調(diào)者將通知事務(wù)參與者準(zhǔn)備提交或取消事務(wù),然后進(jìn)入表決過程。在表決過程中,參與者將告知協(xié)調(diào)者自己的決策:同意(
事務(wù)參與者本地作業(yè)執(zhí)行成功)或取消(本地作業(yè)執(zhí)行故障)。
階段2:提交階段(commit phase)
在該階段,協(xié)調(diào)者將基于第一個(gè)階段的投票結(jié)果進(jìn)行決策:提交或取消。當(dāng)且僅當(dāng)所有的參與者同意提交事務(wù)協(xié)調(diào)者才通知所有的參與者提
交事務(wù),否則協(xié)調(diào)者將通知所有的參與者取消事務(wù)。參與者在接收到協(xié)調(diào)者發(fā)來的消息后將執(zhí)行響應(yīng)的操作。
注意 兩階段提交協(xié)議與兩階段鎖協(xié)議不同,兩階段鎖協(xié)議為一致性控制協(xié)議。
XA
XA是X/Open DTP組織(X/Open DTP group)定義的兩階段提交協(xié)議,XA被許多數(shù)據(jù)庫(如Oracle和DB2)和中間件等工具(如CICS 和
Tuxedo).本地支持 。
X/Open DTP模型(1994)包括應(yīng)用程序(AP)、事務(wù)管理器(TM)、資源管理器(RM)、通信資源管理器(CRM)四部分。在這個(gè)模型中,
通常事務(wù)管理器(TM)是交易中間件,資源管理器(RM)是數(shù)據(jù)庫,通信資源管理器(CRM)是消息中間件。
一般情況下,某一數(shù)據(jù)庫無法知道其它數(shù)據(jù)庫在做什么,因此,在一個(gè)DTP環(huán)境中,交易中間件是必需的,由它通知和協(xié)調(diào)相關(guān)數(shù)據(jù)庫的提
交或回滾。而一個(gè)數(shù)據(jù)庫只將其自己所做的操作(可恢復(fù))影射到全局事務(wù)中。
XA就是X/Open DTP定義的交易中間件與數(shù)據(jù)庫之間的接口規(guī)范(即接口函數(shù)),交易中間件用它來通知數(shù)據(jù)庫事務(wù)的開始、結(jié)束以及提交、
回滾等。XA接口函數(shù)由數(shù)據(jù)庫廠商提供。通常情況下,交易中間件與數(shù)據(jù)庫通過XA 接口規(guī)范,使用兩階段提交來完成一個(gè)全局事務(wù),XA規(guī)
范的基礎(chǔ)是兩階段提交協(xié)議。
MySQL分布式XA事務(wù)
XA–eXtended Architecture 在事務(wù)中意為分布式事務(wù)
XA由協(xié)調(diào)者(coordinator,一般為transaction manager)和參與者(participants,一般在各個(gè)資源上有各自的resource manager)共同完成。在MySQL中,XA事務(wù)有兩種。
內(nèi)部XA事務(wù)
mysql本身的插件式架構(gòu)導(dǎo)致在其內(nèi)部需要使用XA事務(wù),此時(shí)MySQL即是協(xié)調(diào)者,也是參與者。例如,不同的存儲(chǔ)引擎之間是完全獨(dú)立的,因此當(dāng)一個(gè)事務(wù)涉及兩個(gè)不同的存儲(chǔ)引擎時(shí),就必須使用內(nèi)部XA事務(wù)。需要特別注意的是,如果將二進(jìn)制日志看做一個(gè)獨(dú)立的“存儲(chǔ)引擎”,就不難理解為什么即使是一個(gè)存儲(chǔ)引擎參與的事務(wù)也需要使用XA事務(wù)了。在向存儲(chǔ)引擎提交數(shù)據(jù)時(shí),同時(shí)需要將提交的信息寫入二進(jìn)制日志,這就是一個(gè)分布式事務(wù)。
下面的SQL就實(shí)現(xiàn)了一個(gè)簡單的MySQL XA事務(wù):
<pre>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) </pre>
外部XA事務(wù)
MySQL也可以僅作為一個(gè)外部XA的參與者。例如在Java程序中實(shí)現(xiàn)一個(gè)操作多個(gè)異構(gòu)數(shù)據(jù)庫數(shù)據(jù)的分布式事務(wù),則分工為:
Transaction Manager
javax.transaction.xa.XAResource, or Java::BitronixTm(aka “Transaction Coordinator”) 也就是程序本身
Resource Managers
MySQL, PostgreSQL, Oracle, Redis, MQueue, MongoDB, etc.(aka “cohorts”) 即各個(gè)數(shù)據(jù)庫。也就是說只要是提供了相應(yīng)接口的數(shù)據(jù)庫產(chǎn)品就可以作為XA的參與者
Two-phase commit
XA一般由兩階段完成,稱為two-phase commit(2PC)。
階段一為準(zhǔn)備階段,即所有的參與者準(zhǔn)備執(zhí)行事務(wù)并鎖住需要的資源。參與者ready時(shí),向transaction manager匯報(bào)自己已經(jīng)準(zhǔn)備好。
階段二為提交階段。當(dāng)transaction manager確認(rèn)所有參與者都ready后,向所有參與者發(fā)送commit命令。
如下圖所示:
[圖片上傳失敗...(image-dd3598-1585407318371)]
XA的性能問題
XA的性能很低。一個(gè)數(shù)據(jù)庫的事務(wù)和多個(gè)數(shù)據(jù)庫間的XA事務(wù)性能對(duì)比可發(fā)現(xiàn),性能差10倍左右。因此要盡量避免XA事務(wù),例如可以將數(shù)據(jù)寫入本地,用高性能的消息系統(tǒng)分發(fā)數(shù)據(jù)?;蚴褂脭?shù)據(jù)庫復(fù)制等技術(shù)。
只有在這些都無法實(shí)現(xiàn),且性能不是瓶頸時(shí)才應(yīng)該使用XA。
最后是MySQL的XA官方文檔:
http://dev.mysql.com/doc/refman/5.7/en/xa.html
詳解Mysql分布式事務(wù)XA(跨數(shù)據(jù)庫事務(wù))
在開發(fā)中,為了降低單點(diǎn)壓力,通常會(huì)根據(jù)業(yè)務(wù)情況進(jìn)行分表分庫,將表分布在不同的庫中(庫可能分布在不同的機(jī)器上)。在這種場景下,事務(wù)的提交會(huì)變得相對(duì)復(fù)雜,因?yàn)槎鄠€(gè)節(jié)點(diǎn)(庫)的存在,可能存在部分節(jié)點(diǎn)提交失敗的情況,即事務(wù)的ACID特性需要在各個(gè)不同的數(shù)據(jù)庫實(shí)例中保證。比如更新db1庫的A表時(shí),必須同步更新db2庫的B表,兩個(gè)更新形成一個(gè)事務(wù),要么都成功,要么都失敗。
那么我們?nèi)绾卫胢ysql實(shí)現(xiàn)分布式數(shù)據(jù)庫的事務(wù)呢?
Mysql 為我們提供了分布式事務(wù)解決方案(https://dev.mysql.com/doc/refman/5.7/en/xa.html 這是mysql5.7的文檔)
這里先聲明兩個(gè)概念:
- 資源管理器(resource manager):用來管理系統(tǒng)資源,是通向事務(wù)資源的途徑。數(shù)據(jù)庫就是一種資源管理器。資源管理還應(yīng)該具有管理事務(wù)提交或回滾的能力。
-
事務(wù)管理器(transaction manager):事務(wù)管理器是分布式事務(wù)的核心管理者。事務(wù)管理器與每個(gè)資源管理器(resource
manager)進(jìn)行通信,協(xié)調(diào)并完成事務(wù)的處理。事務(wù)的各個(gè)分支由唯一命名進(jìn)行標(biāo)識(shí)。
mysql在執(zhí)行分布式事務(wù)(外部XA)的時(shí)候,mysql服務(wù)器相當(dāng)于xa事務(wù)資源管理器,與mysql鏈接的客戶端相當(dāng)于事務(wù)管理器。
分布式事務(wù)原理:分段式提交
分布式事務(wù)通常采用2PC協(xié)議,全稱Two Phase Commitment Protocol。該協(xié)議主要為了解決在分布式數(shù)據(jù)庫場景下,所有節(jié)點(diǎn)間數(shù)據(jù)一致性的問題。分布式事務(wù)通過2PC協(xié)議將提交分成兩個(gè)階段:
- prepare;
- commit/rollback
階段一為準(zhǔn)備(prepare)階段。即所有的參與者準(zhǔn)備執(zhí)行事務(wù)并鎖住需要的資源。參與者ready時(shí),向transaction manager報(bào)告已準(zhǔn)備就緒。
階段二為提交階段(commit)。當(dāng)transaction manager確認(rèn)所有參與者都ready后,向所有參與者發(fā)送commit命令。
如下圖所示:
[圖片上傳失敗...(image-374a7-1585407318371)]
事務(wù)協(xié)調(diào)者transaction manager
因?yàn)閄A 事務(wù)是基于兩階段提交協(xié)議的,所以需要有一個(gè)事務(wù)協(xié)調(diào)者(transaction manager)來保證所有的事務(wù)參與者都完成了準(zhǔn)備工作(第一階段)。如果事務(wù)協(xié)調(diào)者(transaction manager)收到所有參與者都準(zhǔn)備好的消息,就會(huì)通知所有的事務(wù)都可以提交了(第二階段)。MySQL 在這個(gè)XA事務(wù)中扮演的是參與者的角色,而不是事務(wù)協(xié)調(diào)者(transaction manager)。
Mysql的XA事務(wù)分為外部XA和內(nèi)部XA
- 外部XA用于跨多MySQL實(shí)例的分布式事務(wù),需要應(yīng)用層作為協(xié)調(diào)者,通俗的說就是比如我們在PHP中寫代碼,那么PHP書寫的邏輯就是協(xié)調(diào)者。應(yīng)用層負(fù)責(zé)決定提交還是回滾,崩潰時(shí)的懸掛事務(wù)。MySQL數(shù)據(jù)庫外部XA可以用在分布式數(shù)據(jù)庫代理層,實(shí)現(xiàn)對(duì)MySQL數(shù)據(jù)庫的分布式事務(wù)支持,例如開源的代理工具:網(wǎng)易的DDB,淘寶的TDDL等等。
- 內(nèi)部XA事務(wù)用于同一實(shí)例下跨多引擎事務(wù),由Binlog作為協(xié)調(diào)者,比如在一個(gè)存儲(chǔ)引擎提交時(shí),需要將提交信息寫入二進(jìn)制日志,這就是一個(gè)分布式內(nèi)部XA事務(wù),只不過二進(jìn)制日志的參與者是MySQL本身。Binlog作為內(nèi)部XA的協(xié)調(diào)者,在binlog中出現(xiàn)的內(nèi)部xid,在crash recover時(shí),由binlog負(fù)責(zé)提交。(這是因?yàn)?,binlog不進(jìn)行prepare,只進(jìn)行commit,因此在binlog中出現(xiàn)的內(nèi)部xid,一定能夠保證其在底層各存儲(chǔ)引擎中已經(jīng)完成prepare)。
MySQL XA事務(wù)基本語法
XA {START|BEGIN} xid [JOIN|RESUME] 啟動(dòng)xid事務(wù) (xid 必須是一個(gè)唯一值; 不支持[JOIN|RESUME]子句)
XA END xid [SUSPEND [FOR MIGRATE]] 結(jié)束xid事務(wù) ( 不支持[SUSPEND [FOR MIGRATE]] 子句)
XA PREPARE xid 準(zhǔn)備、預(yù)提交xid事務(wù)
XA COMMIT xid [ONE PHASE] 提交xid事務(wù)
XA ROLLBACK xid 回滾xid事務(wù)
XA RECOVER 查看處于PREPARE 階段的所有事務(wù)
PHP調(diào)用MYSQL XA事務(wù)示例
1、首先要確保mysql開啟XA事務(wù)支持
<pre class="prettyprint">SHOW VARIABLES LIKE '%xa%'</pre>
如果innodb_support_xa的值是ON就說明mysql已經(jīng)開啟對(duì)XA事務(wù)的支持了。
如果不是就執(zhí)行:
<pre class="prettyprint">SET innodb_support_xa = ON</pre>
開啟
2、代碼如下:
<pre class="prettyprint"><!--?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事務(wù)指定一個(gè)id,xid 必須是一個(gè)唯一值。 $xid = uniqid(""); //兩個(gè)庫指定同一個(gè)事務(wù)id,表明這兩個(gè)庫的操作處于同一事務(wù)中 $dbtest1->query("XA START '$xid'");//準(zhǔn)備事務(wù)1 $dbtest2->query("XA START '$xid'");//準(zhǔn)備事務(wù)2 try { //$dbtest1 $return = $dbtest1->query("UPDATE member SET name='唐大麥' WHERE id=1") ; if($return == false) {
throw new Exception("庫dbtest1@172.20.101.17執(zhí)行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執(zhí)行update memberpoints操作失敗!");
} //階段1:$dbtest1提交準(zhǔn)備就緒 $dbtest1->query("XA END '$xid'"); $dbtest1->query("XA PREPARE '$xid'"); //階段1:$dbtest2提交準(zhǔn)備就緒 $dbtest2->query("XA END '$xid'"); $dbtest2->query("XA PREPARE '$xid'"); //階段2:提交兩個(gè)庫 $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(); ?></pre>
XA的性能問題
XA的性能很低。一個(gè)數(shù)據(jù)庫的事務(wù)和多個(gè)數(shù)據(jù)庫間的XA事務(wù)性能對(duì)比可發(fā)現(xiàn),性能差10倍左右。因此要盡量避免XA事務(wù),例如可以將數(shù)據(jù)寫入本地,用高性能的消息系統(tǒng)分發(fā)數(shù)據(jù)?;蚴褂脭?shù)據(jù)庫復(fù)制等技術(shù)。只有在這些都無法實(shí)現(xiàn),且性能不是瓶頸時(shí)才應(yīng)該使用XA。