天天看點

MySQL · 特性分析 · 淺談 MySQL 5.7 XA 事務改進

關于MySQL XA 事務

MySQL XA 事務通常用于分布式事務處理當中。比如在分庫分表的場景下,當遇到一個使用者事務跨了多個分區,需要使用XA事務 來完成整個事務的正确的送出和復原,即保證全局事務的一緻性。

XA 事務在分庫分表場景的使用

下圖是個典型的分庫分表場景,前端是一個Proxy後面帶若幹個MySQL執行個體,每個執行個體是一個分區。

MySQL · 特性分析 · 淺談 MySQL 5.7 XA 事務改進

假設一個表test定義如下,Proxy根據主鍵”a”算Hash決定一條記錄應該分布在哪個節點上:

應用發到Proxy的一個事務如下:

Proxy收到這個事務需要将它轉成XA事務發送到後端的資料庫以保證這個事務能夠安全的送出或復原,一般的Proxy的處理步驟 如下:

Proxy先收到begin,它隻需要設定一下自己的狀态不需要向後端資料庫發送

當收到 insert 語句時Proxy會解析語句,根據“a”的值計算出該條記錄應該位于哪個節點上,這裡假設是“分庫1”

Proxy就會向分庫1上發送語句xa start ‘xid1’,開啟一個XA事務,這裡xid1是Proxy自動生成的一個全局事務ID;同時原來 的insert語句insert into values(1,1)也會一并發送到分庫1上。

這時Proxy遇到了update語句,Proxy會解析 where條件主鍵的值來決定該條語句會被發送到哪個節點上,這裡假設是“分庫2”

Proxy就會向分庫2上發送語句xa start ‘xid1’,開啟一個XA事務,這裡xid1是Proxy之前已經生成的一個全局事務ID;同時原來 的update語句update test set b = 1 where a = 10也會一并發送到分庫2上。

最後當Proxy解析到commit語句時,就知道一個使用者事務已經結束了,就開啟送出流程

Proxy會向分庫1和分庫2發送 xa end ‘xid1’;xa prepare ‘xid1’語句,當收到執行都成功回複後,則繼續進行到下一步,如果任何一個分 庫傳回失敗,則向分庫1和分庫2 發送 xa rollback ‘xid1’,復原整個事務

當 xa prepare ‘xid1’都傳回成功,那麼 proxy會向分庫1和分庫2上發送 xa commit ‘xid1’,來最終送出事務。

這裡有一個可能的優化,即在步驟4時如果Proxy計算出update語句發送的節點仍然是“分庫1”時,在遇到commit時,由于隻涉 及到一個分庫,它可以直接向“分庫1”發送 xa end ‘xid1’; xa commit ‘xid1’ one phase來直接送出該事務,避免走 prepare階段來提高效率。

XA對事務安全的影響分析

從以上分庫分表場景下分布式事務的處理過程來看,整個分布式事務的安全性依賴是XA Prepare了的事務的可靠性,也就是在 資料庫節點上 XA Prepare了的事務必須是持久化了的,這樣當XA Commit發來時才可以送出。設想如下場景:

Proxy已經向分庫1和分庫2上發送完了 xa prepare ‘xid1’語句,并得到了成功的回複

Proxy向分庫1上發送了 ‘xa commit ‘xid1’語句,并已經成功傳回

當 Proxy向分庫2上發送 ‘xa commit ‘xid1’時,網絡斷開了,或者分庫2的資料庫執行個體被kill了

當網絡恢複(這時相關的Session已經退出了)或資料庫執行個體再啟動後(或切換到備庫),XA prepare了的事務已經復原了, 當Proxy XA commit ‘xid1’發過來後資料庫執行個體根本找不到xid1這個xa事務

上面的過程就導緻了分布式事務的不一緻:分庫1送出了事務,分庫2復原了事務,整個事務送出了一半,復原了一半。

在MySQL 5.6中以上過程是可能發生的,因為xa prepare并沒有嚴格的持久化,當Session斷開,資料庫崩潰等情況下這些事務 會被復原掉,而且的當一個主庫配置了SemiSync的備庫時xa prepare了的事務也不會被發送的備庫,如果主庫切換到備庫這些 事務也會丢失。

MySQL 5.7 XA可靠性改進

MySQL 5.7解決了 xa prepare了的事務的嚴格持久化問題,也就是在session斷開和執行個體崩潰重新開機情況下這些事務不丢,同時在 xa prepare ‘xid1’傳回之前XA事務也會同步到備庫。下面将通過在5.6和5.7上分别執行xa prepare并對binlog event進行分析 來示範這個改進。

斷開連接配接對xa prepare的事務影響

在5.6和5.7上分别執行如下sql然後斷開連接配接,再重新連接配接使用的xa recover驗證 XA 事務是否復原了。

在 5.6 的版本上将傳回空的結果,在 5.7 的版本上傳回:

說明斷開連接配接後 5.7的prepare了的xa事務沒有丢失。

XA 事務的 Binlog events 異同

在5.6和5.7上分别執行如下事務,然後用 show binlog events 檢視兩者binlog的不同:

5.6的結果:

5.7的結果:

可以看到 MySQL 5.6 XA 事務和普通事務的binlog是一樣的,并沒有展現 xa prepare。而到了 MySQL 5.7 XA 事務的binlog和 普通的事務是完全不同的,XA Prepare有單獨的Log event類型,有自己的Gtid,當開啟semi-sync的情況下,MySQL 5.7 執行 XA prepare 時會等備庫回複後才傳回結果給用戶端,這樣XA prepare執行完就是安全的。

通過以上分析可以看出 MySQL 5.7在XA事務安全性方面做了很大的改進,後續月封包章将會對它的實作做分析。