您好,登錄后才能下訂單哦!
本篇內容主要講解“MySQL 5.7的分布式事務支持舉例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“MySQL 5.7的分布式事務支持舉例分析”吧!
分布式事務通常采用2PC協議,全稱Two Phase Commitment Protocol。該協議主要為了解決在分布式數據庫場景下,所有節點間數據一致性的問題。在分布式事務環境下,事務的提交會變得相對比較復雜,因為多個節點的存在,可能存在部分節點提交失敗的情況,即事務的ACID特性需要在各個數據庫實例中保證。總而言之,在分布式提交時,只要發生一個節點提交失敗,則所有的節點都不能提交,只有當所有節點都能提交時,整個分布式事務才允許被提交。
分布式事務通過2PC協議將提交分成兩個階段
prepare;
commit/rollback
第一階段的prepare只是用來詢問每個節點事務是否能提交,只有當得到所有節點的“許可”的情況下,第二階段的commit才能進行,否則就rollback。需要注意的是:prepare成功的事務,則必須全部提交。
一直以來,MySQL數據庫是支持分布式事務的,但是只能說是有限的支持,具體表現在:
已經prepare的事務,在客戶端退出或者服務宕機的時候,2PC的事務會被回滾
在服務器故障重啟提交后,相應的Binlog被丟失
上述問題存在于MySQL數據庫長達數十年的時間,直到MySQL-5.7.7版本,官方才修復了該問題。雖然InnoSQL早已在5.5版本修復,但是對比官方的修復方案,我們真的做的沒有那么的優雅。下面將會詳細介紹下該問題的具體表現和官方修復方法,這里分別采用官方MySQL-5.6.27版本(未修復)和MySQL-5.7.9版本(已修復)進行驗證。
先來看下存在的問題,我們先創建一個表如下:
create table t( id int auto_increment primary key, a int )engine=innodb;
對于上述表,通過如下操作進行數據插入:
mysql> XA START 'mysql56'; mysql> INSERT INTO t VALUES(1,1); mysql> XA END 'mysql56'; mysql> XA PREPARE 'mysql56'
通過上面的操作,用戶創建了一個分布式事務,并且prepare沒有返回錯誤,說明該分布式事務可以被提交。通過命令XA RECOVER查看顯示如下結果:
mysql> XA RECOVER; +----------+--------------+--------------+---------+ | formatID | gtrid_length | bqual_length | data | +----------+--------------+--------------+---------+ | 1 | 7 | 0 | mysql56 | +----------+--------------+--------------+---------+
若這時候用戶退出客戶端后重連,通過命令xa recover會發現剛才創建的2PC事務不見了。即prepare成功的事務丟失了,不符合2PC協議規范!!!
產生上述問題的主要原因在于:MySQL-5.6版本在客戶端退出的時候,自動把已經prepare的事務回滾了,那么MySQL為什么要這樣做?這主要取決于MySQL的內部實現,MySQL-5.7以前的版本,對于prepare的事務,MySQL是不會記錄binlog的(官方說是減少fsync,起到了優化的作用)。只有當分布式事務提交的時候才會把前面的操作寫入binlog信息,所以對于binlog來說,分布式事務與普通的事務沒有區別,而prepare以前的操作信息都保存在連接的IO_CACHE中,如果這個時候客戶端退出了,以前的binlog信息都會被丟失,再次重連后允許提交的話,會造成Binlog丟失,從而造成主從數據的不一致,所以官方在客戶端退出的時候直接把已經prepare的事務都回滾了!
官方的做法,貌似干得很漂亮,犧牲了一點標準化的東西,至少保證了主從數據的一致性。但其實不然,若用戶已經prepare后在客戶端退出之前,MySQL發生了宕機,這個時候又會怎樣?
MySQL在某個分布式事務prepare成功后宕機,宕機前操作該事務的連接并沒有斷開,這個時候已經prepare的事務并不會被回滾,所以在MySQL重新啟動后,引擎層通過recover機制能恢復該事務。當然該事務的Binlog已經在宕機過程中被丟失,這個時候,如果去提交,則會造成主從數據的不一致,即提交沒有記錄Binlog,從上丟失該條數據。所以對于這種情況,官方一般建議直接回滾已經prepare的事務。
以上是MySQL-5.7以前版本MySQL在分布式事務上的各種問題,那么MySQL-5.7版本官方做了哪些改進?這個可以從官方的WL#6860描述上得到一些信息,我們還是本著沒有實踐就沒有發言權的態度,從具體的操作上來分析下MySQL-5.7的改進方法:
還是以上面同樣的表結構進行同樣的操作如下:
mysql> XA START 'mysql57'; mysql> INSERT INTO t VALUES(1,1); mysql> XA END 'mysql57'; mysql> XA PREPARE 'mysql57'通過上面的操作,明顯發現在prepare以后,從XA START到XA PREPARE之間的操作都被記錄到了Master的Binlog中,然后通過復制關系傳到了Slave上。也就是說MySQL-5.7開始,MySQL對于分布式事務,在prepare的時候就完成了寫Binlog的操作,通過新增一種叫
當然僅靠這一點是不夠的,因為我們知道Slave通過SQL thread來回放Relay log信息,由于prepare的事務能阻塞整個session,而回放的SQL thread只有一個(不考慮并行回放),那么SQL thread會不會因為被分布式事務的prepare階段所阻塞,從而造成整個SQL thread回放出現問題?這也正是官方要解決的第二個問題:怎么樣能使SQL thread在回放到分布式事務的prepare階段時,不阻塞后面event的回放?其實這個實現也很簡單(在xa.cc::applier_reset_xa_trans),只要在SQL thread回放到prepare的時候,進行類似于客戶端斷開連接的處理即可(把相關cache與SQL thread的連接句柄脫離)。最后在Slave服務器上,用戶通過命令XA RECOVER可以查到如下信息:
mysql> XA RECOVER; +----------+--------------+--------------+---------+ | formatID | gtrid_length | bqual_length | data | +----------+--------------+--------------+---------+ | 1 | 7 | 0 | mysql57 | +----------+--------------+--------------+---------+
至于上面的事務什么時候提交,一般等到Master上進行XA COMMIT ‘mysql57’后,slave上也同時會被提交。
到此,相信大家對“MySQL 5.7的分布式事務支持舉例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。