溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

一文教你迅速解決分布式事務XA一致性問題

發(fā)布時間:2020-08-13 09:09:55 來源:ITPUB博客 閱讀:240 作者:克勞德同學 欄目:云計算

近日,騰訊云發(fā)布了分布式數(shù)據(jù)庫解決方案(DCDB),其最明顯的特性之一就是提供了高于開源分布式事務XA的性能。大型業(yè)務系統(tǒng)有著用戶多、并發(fā)高的特點,在這方面,集中式數(shù)據(jù)庫(單機數(shù)據(jù)庫)的性能很難支持,因此主流的互聯(lián)網(wǎng)公司往往采用分布式(架構)數(shù)據(jù)庫,物理上利用更多的低端設備,邏輯上對大表水平拆分支撐業(yè)務的需要。

雖然分布式數(shù)據(jù)庫能解決性能難題,但事務一致性(Consistency)的問題,卻很難在分布式數(shù)據(jù)庫上得到解決。

分布式事務老大難題,數(shù)據(jù)一致難以實現(xiàn)

眾所周知,一個事務所做的更新,分布式數(shù)據(jù)庫系統(tǒng)內部多個獨立的數(shù)據(jù)節(jié)點完成(每個節(jié)點的本地事務是這個全局事務的一個事務分支),在這樣一個全局事務提交期間,有可能某些事務分支無法成功提交。

針對這一問題,雖然業(yè)內早已存在理論解決方案——二階段提交協(xié)議(簡稱2PC),并延伸出分布式事務(簡稱XA)的解決方案。但業(yè)內卻少有工程化實現(xiàn)且大規(guī)模應用的案例。而騰訊云分布式數(shù)據(jù)庫DCDB,卻已在內部業(yè)務中應用多年。

一文教你迅速解決分布式事務XA一致性問題

(圖:二階段提交算法)

目前DCDB已應用在騰訊內部90%以上的交易、計費業(yè)務,并且三一重工(樹根互聯(lián))、匯通天下(G7)、閱文集團(起點/創(chuàng)世中文網(wǎng)等)、微眾銀行、和泰人壽、威富通等都在該產品。

騰訊云首發(fā)分布式數(shù)據(jù)庫XA,支持MySQL 5.7

騰訊云分布式數(shù)據(jù)庫DCDB,是基于騰訊金融級數(shù)據(jù)庫(公司內部代號TDSQL)云化改造而來的兼容MySQL協(xié)議的分布式數(shù)據(jù)庫?,F(xiàn)如今,騰訊云DCDB已經正式在MySQL 5.7(percona分支)協(xié)議上支持分布式事務XA,并已在騰訊云公有云、金融云發(fā)布供開發(fā)者使用。開發(fā)者可以通過申請DCDB實例,并在初始化后,連接實例運行如下sql進行初始化:

 

MySQL> xa init;

Query OK, 0 rows affected (0.03 sec)


注意:初始化xa前,請開啟強同步復制能力,另外該sql會創(chuàng)建xa.gtid_log_t,用戶在后續(xù)使用中萬勿對其進行任何操作。。

為更好的支持分布式事務,DCDB還新增了SQL命令:

1)  SELECT gtid(),獲取當前分布式事務的gtid(事務的全局唯一性標識),如果該事務不是分布式事務則返回空;

    gtid的格式:

    ‘網(wǎng)關id’-‘網(wǎng)關隨機值’-‘序列號’-‘時間戳’-‘分區(qū)號’,例如 c46535fe-b6-dd-595db6b8-25


2)  SELECT gtid_state(“gtid”),獲取“gtid”的狀態(tài),可能的結果有:

    a)  “COMMIT”,標識該事務已經或者最終會被提交

    b)  “ABORT”,標識該事務最終會被回滾

    c)  空,由于事務的狀態(tài)會在一個小時之后清楚,因此有以下兩種可能:

            1) 一個小時之后查詢,標識事務狀態(tài)已經清除

            2) 一個小時以內查詢,標識事務最終會被回滾


3) 運維命令:

    xa recover:向后端SET發(fā)送xa recover命令,并進行匯總

    xa lockwait:顯示當前分布式事務的等待關系(可以使用dot命令將輸出轉化為等待關系圖)

    xa show:當前網(wǎng)關上正在運行的分布式事務

Python為例,可以對轉賬業(yè)務進行如下編碼:   

    db = pyMySQL.connect(host=testHost, port=testPort, user=testUser, password=testPassword, database=testDatabase)

    cursor = db.cursor()

    try:

        cursor.execute("begin")


        #為一個賬戶Bob的余額減1

        query = "update t_user_balance SET balance = balance - 1  where user='Bob' and balance>1)

        affected = cursor.execute(query)

        if affected == 0: #余額不足,回滾事務

            cursor.execute("rollback")

            return


        #為一個賬戶John的余額加1

        query = "update t_user_balance SET balance = balance + 1  where user='John')

        cursor.execute(query)


        # 為了安全起見,建議在這里執(zhí)行‘SELECT gtid()’獲取當前事務的id值,便于后續(xù)跟蹤事務的執(zhí)行情況


        #提交事務

        cursor.execute("commit")

    except pyMySQL.err.MySQLError as e:

        # 發(fā)生故障,回滾事務

        cursor.execute("rollback")

分布式事務的好處在于會大大降低應用開發(fā)難度,因為在某些不支持XA的數(shù)據(jù)庫中,需要業(yè)務系統(tǒng)通過特殊并且巧妙的設計,而非利用數(shù)據(jù)庫來解決事務中數(shù)據(jù)不一致等問題。這種對應用開發(fā)者的技術水平要求很高,越是復雜的業(yè)務系統(tǒng),越會增加開發(fā)成本和技術門檻,這是業(yè)內大多數(shù)開發(fā)者面對分布式數(shù)據(jù)庫時,只能望而卻步的主要原因。

騰訊云DCDB XA關鍵實現(xiàn)方案

1DCDB架構介紹

騰訊云DCDB整個集群架構簡圖如下圖,MySQL采用主從節(jié)點配置(也叫作主備)一套主從節(jié)點叫做SET,在每一個SET外配置網(wǎng)關(TProxy),形成一個物理分片(Shard)。一文教你迅速解決分布式事務XA一致性問題

DCDB后端是MySQL(或其分支版本)數(shù)據(jù)庫,目前騰訊云公有云發(fā)布支持XA的版本是基于MySQL 5.7.17percona分支)。

2、網(wǎng)關(TProxy)與XA

網(wǎng)關是用于接收請求并與后端MySQL建立連接的網(wǎng)絡模塊。網(wǎng)關可以用兩種模式工作,一種稱為noshard,此模式下網(wǎng)關不處理/不解析SQL語句,透明轉發(fā)請求和應答。另一種模式稱為shard(分布式,即支持自動水平分表)模式下,TProxy會解析SQL并轉發(fā)到不同的數(shù)據(jù)分片。

在實現(xiàn)XA之前,網(wǎng)關不允許在一個事務中向多個SET發(fā)送DML語句。因為未實現(xiàn)二階段提交(2PC)時,事務采用一階段提交,如果分布式中某一個SET提交失敗了或回滾了,那么這個分布式事務就處于不一致的狀態(tài)。

一文教你迅速解決分布式事務XA一致性問題

(網(wǎng)關的工作方式)

二階段提交中需要的事務管理器TM)。為了解決容災、簡化架構,騰訊云DCDBTM實現(xiàn)在TProxy中,而DCDB的網(wǎng)關是一個無狀態(tài)的模塊,通過這一架構,DCDB XA可以支持:

1、分布式事務對業(yè)務透明,兼容單機事務語法(start transaction/commit/rollback/savepoint)。

2、每個網(wǎng)關都可以獨立接受和處理事務請求,且無需與其他網(wǎng)關進行協(xié)調節(jié)點故障不丟失事務。

3、允許顯式事務中多條語句分別發(fā)給多個分片。

4、網(wǎng)關無需持久狀態(tài),無需容災,可以隨時經由調度集群退出或加入集群,且性能可以擴展。

5、支持autocommit下單條語句寫訪問多個分片等。

DCDB網(wǎng)關還允許以流式處理方式運行group by、order by,流式處理讓這類操作變得非常方式非常高效;網(wǎng)關還支持兩個Shard使用shardkey(分表鍵)做等值連接,以及使用shardkey的子查詢。

未來,騰訊云還計劃支持分布式JOIN、Sparksql、二級分區(qū)等高級功能,兼容更多MySQL高級語法。

3、強同步與XA

由于騰訊云DCDB默認采用強同步復制,即主從節(jié)點數(shù)據(jù)完全一致,因此XA事務也遵循強同步的邏輯,即需等待從機確認數(shù)據(jù)同步后,才給業(yè)務以應答(commit)。基于強同步,在以下兩種異常情況下,DCDB XA可輕松應對

1、主節(jié)點故障時,已確認事務數(shù)據(jù)不會丟失:主節(jié)點故障那么擁有最新數(shù)據(jù)和binlog的從機就被選為主節(jié)點,這其中的數(shù)據(jù)也包括所有已經向用戶確認完成提交的事務的數(shù)據(jù)。

2、原主節(jié)點恢復后重新加入集群,未確認事務自動閃回:原主節(jié)點恢復重新接入集群,它將作為從機運行,此時他可能存留多余的已提交事務(此時事務并未得到強同步同步確認,即原備機并沒有相關數(shù)據(jù)),那么這些事務會被閃回。雖然這些事務可能已經在原主節(jié)點的MySQL內部完成提交,但由于強同步機制,他并不會向客戶端返回commit語句,這意味著仍被視為一個未完成的事務。因此,這些事務的閃回了也并沒有破壞數(shù)據(jù)庫的ACID屬性。這里值得說的是,閃回flashback是基于binlog生成做逆操作,它與數(shù)據(jù)庫回滾并不同rollback,閃回可以做DDL操作。

騰訊云DCDB的強同步為騰訊金融級數(shù)據(jù)庫自研的一項能力,性能比官方半同步大幅提高,幾乎等于異步復制性能,騰訊云DCDB在騰訊內部應用多年,未發(fā)生過一起因為主從切換、故障帶來的數(shù)據(jù)誤差。而且,從性能上,也撐住了騰訊公司各類大型運營活動如紅包、各類游戲大型推廣等海量并發(fā),其主要原因是強同步采用異步提交/等待方式,且不占用數(shù)據(jù)庫工作線程。

4、并發(fā)控制與隔離級別

為了達到數(shù)據(jù)一致性和性能的平衡,分布式事務的關鍵是數(shù)據(jù)庫隔離控制。XA的隔離級別最高可以達到serializable(完全串行化),該級別將不存在幻讀的問題,serializable級別可以通過設置SET global tx_isolation='serializable'來對DCDB所有物理分片(和其上承載的MySQL數(shù)據(jù)庫)進行設置。當然,也可以通過調整隔離級別以調整數(shù)據(jù)庫實例性能,理論上,Read Uncommitted性能最高,但可能存在臟讀、幻讀的情況。

隔離解別

臟讀

不可重復讀

幻讀

Read Uncommitted

Y

Y

Y

Read Committed

N

Y

Y

Repeatable(default)

N

N

Y

Serializable

N

N

N

(ANSI/ISO定義的SQL-92標準定義的四種隔離級別)

5、分布式事務處理算法

前面講到,騰訊云DCDB的網(wǎng)關在shard模式下已經能夠解析SQL語句,騰訊云在網(wǎng)關上實現(xiàn)TM以使得XA最具效率。為此,我們在網(wǎng)關中實現(xiàn)TM中的協(xié)調器(coordinator),并在網(wǎng)關中維護每個XA的狀態(tài),記錄好每個XA寫入的SET,然后在提交階段做兩階段提交即可,大致流程如下:

一文教你迅速解決分布式事務XA一致性問題

1、網(wǎng)關在執(zhí)行一個事務的insert/update/delete語句時,會記錄這個語句修改了哪個SET

2、SET時會發(fā)送一個XA START在這個SET上面啟動事務分支;(注:XA事務開始時,并不確認事務將以哪種提交方式執(zhí)行,因此總是以xa start來開啟一個事務)

3、檢測是否影響SET個數(shù)≤1,若是,則直接做一階段提交(xa commit one phase)。

4、影響SET個數(shù)≥2,則改為做兩階段提交

1)網(wǎng)關首先發(fā)送xa prepare gtid’ 給參與的SET(大于等于2SET

2)SET接受到xa prepare應答ok(表示成功確認)

3)收到成功確認后,寫入XA對應的commit log,再發(fā)送xa commit gtid’參與SET。

4)如果有SET返回了錯誤,或者寫入commit log失敗,那么網(wǎng)關發(fā)送 xa rollback gtid’ 給相關SET,這樣這個全局事務就實現(xiàn)了回滾。

騰訊云DCDBcommit log是在SET中存儲,這個步驟是批量完成的——網(wǎng)關后臺線程會匯集正在提交的分布式事務然后在獨立的連接和事務中完成對每個SET的寫入,并且每個事務的commit log只寫入一個SET中,因而這個開銷并沒有顯著增加事務的提交耗時或者降低TPS。而且,依賴騰訊云DCDB已有的強同步和容災特性,只要XA成功寫入了commit log,就意味著數(shù)據(jù)已經寫入從機。

雖然絕大多數(shù)的XA事務可以正常執(zhí)行。但極少數(shù)的異常情況還是會影響整個集群穩(wěn)定性,因此,騰訊云設計了agent(監(jiān)控模塊),在故障后繼續(xù)協(xié)助完成本地MySQL上面prepared事務的提交,即agent會解析commit log,并根據(jù)異常處理本地仍然處于prepared的事務數(shù)據(jù);如果commit log上面沒有事務的提交決定的話,agent也會回滾超時未被提交的prepared本地事務。

雖然在MySQL 5.5、5.6等版本早已實現(xiàn)XA,但這兩個版本相對于5.7仍然有性能不足,因此騰訊云目前只在公有云上基于5.7.17支持XA版本。如今,騰訊云在MySQL 、percona、MariaDB等分支中做了大量優(yōu)化和相關bug修復(部分已經提交到社區(qū)修復patch或開源),未來騰訊云還將繼續(xù)致力于新特性的開發(fā)和相關Bug的修復,為眾多有需要的企業(yè),提供更好的分布式數(shù)據(jù)庫支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI