MySQL XA 事務支持調研

準備往DBScale中添加分佈式事務支持,最合適的方案是使用XA事務。
以下是關於mysql xa事務的調研:

1. mysql xa事務的語法
主要有:
XA START 'any_unique_id';  // 'any_unique_id' 是用戶給的,全局唯一
在一臺mysql中開啓一個XA事務

XA END '
any_unique_id ';
標識XA事務的操作結束
 
XA PREPARE '
any_unique_id';
告知mysql 準備提交這個xa事務

XA COMMIT '
any_unique_id';
告知mysql提交這個xa事務

XA ROLLBACK 'any_unique_id';
告知mysql回滾這個xa事務

XA RECOVER;
查看本機mysql目前有哪些xa事務處於prepare狀態

2. XA事務恢復
如果執行分佈式事務的mysql crash了,mysql 按照如下邏輯進行恢復:
a. 如果這個xa事務commit了,那麼什麼也不用做
b. 如果這個xa事務還沒有prepare,那麼直接回滾它
c. 如果這個xa事務prepare了,還沒commit, 那麼把它恢復到prepare的狀態,由用戶去決定commit或rollback
當mysql crash後重新啓動之後,執行
“XA RECOVER;”查看當前處於prepare狀態的xa事務,然後commit或rollback它們。

3. 使用限制
a. XA事務和本地事務以及鎖表操作是互斥的
開啓了xa事務就無法使用本地事務和鎖表操作
mysql> xa start 't1xa';
Query OK, 0 rows affected (0.04 sec)

mysql> begin;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  ACTIVE state

mysql> lock table t1 read;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  ACTIVE state

開啓了本地事務就無法使用xa事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> xa start 'rrrr';
ERROR 1400 (XAE09): XAER_OUTSIDE: Some work is done outside global transaction

b. xa start 之後必須xa end, 否則不能執行xa commit 和xa rollback
所以如果在執行xa事務過程中有語句出錯了,你也需要先xa end一下,然後才能xarollback。

4. 注意事項

a. mysql只是提供了xa事務的接口,分佈式事務中的mysql實例之間是互相獨立的不感知的。 所以用戶必須
自己實現分佈式事務的調度器
b. xa事務有一些使用上的bug, 參考http://www.mysqlops.com/2012/02/24/mysql-xa-optimize.html
主要是
MySQL數據庫的主備數據庫的同步,通過Binlog的複製完成。而Binlog是MySQL數據庫內部XA事務的協調者,並且MySQL數據庫爲binlog做了優化——binlog不寫prepare日誌,只寫commit日誌。
所有的參與節點prepare完成,在進行xa commit前crash。crash recover如果選擇commit此事務。由於binlog在prepare階段未寫,因此主庫中看來,此分佈式事務最終提交了,但是此事務的操作並未 寫到binlog中,因此也就未能成功複製到備庫,從而導致主備庫數據不一致的情況出現。
而crash recover如果選rollback, 那麼就會出現全局不一致(
該分佈式事務對應的節點,部分已經提交,無法回滾,而部分節點回滾。最終導致同一分佈式事務,在各參與節點,最終狀態不一致

參考的那篇blog中給出的辦法是修改mysql代碼,這個無法在DBScale中使用。 所以可選的替代方案是不使用
主從複製進行備份,而是直接使用xa事務實現同步寫來作爲備份。

轉載請註明出自高孝鑫的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章