騰訊雲分散式資料庫,解決分散式事務XA一致性問題
近日,騰訊雲發布了分散式資料庫解決方案(DCDB),其最明顯的特性之一就是提供了高於開源分散式事務XA的性能。大型業務系統有著用戶多、並發高的特點,在這方面,集中式資料庫(單機資料庫)的性能很難支持,因此主流的互聯網公司往往採用分散式(架構)資料庫,物理上利用更多的低端設備,邏輯上對大表水平拆分支撐業務的需要。
雖然分散式資料庫能解決性能難題,但事務一致性(Consistency)的問題,卻很難在分散式資料庫上得到解決。
分散式事務老大難題,數據一致難以實現
眾所周知,一個事務所做的更新,分散式資料庫系統內部多個獨立的數據節點完成(每個節點的本地事務是這個全局事務的一個事務分支),在這樣一個全局事務提交期間,有可能某些事務分支無法成功提交。
針對這一問題,雖然業內早已存在理論解決方案——二階段提交協議(簡稱2PC),並延伸出分散式事務(簡稱XA)的解決方案。但業內卻少有工程化實現且大規模應用的案例。而騰訊雲分散式資料庫DCDB,卻已在內部業務中應用多年。
(圖:二階段提交演算法)
目前DCDB已應用在騰訊內部90%以上的交易、計費業務,並且三一重工(樹根互聯)、匯通天下(G7)、閱文集團(起點/創世中文網等)、微眾銀行、和泰人壽、威富通等都在該產品。
騰訊雲首發分散式資料庫XA,支持MySQL 5.7
騰訊雲分散式資料庫DCDB,是基於騰訊金融級資料庫(公司內部代號TDSQL)雲化改造而來的兼容MySQL協議的分散式資料庫。現如今,騰訊雲DCDB已經正式在MySQL 5.7(percona分支)協議上支持分散式事務XA,並已在騰訊雲公有雲、金融雲發布供開發者使用。開發者可以通過申請DCDB實例,並在初始化後,連接實例運行如下sql進行初始化:
MySQL> xa init;
Query OK, 0 rows affected (0.03 sec)
注意:初始化xa前,請開啟強同步複製能力,另外該sql會創建xa.gtid_log_t,用戶在後續使用中萬勿對其進行任何操作。。
為更好的支持分散式事務,DCDB還新增了SQL命令:
1) SELECT gtid,獲取當前分散式事務的gtid(事務的全局唯一性標識),如果該事務不是分散式事務則返回空;
gtid的格式:
『網關id』-『網關隨機值』-『序列號』-『時間戳』-『分區號』,例如 c46535fe-b6-dd-595db6b8-25
2) SELECT gtid_state(「gtid」),獲取「gtid」的狀態,可能的結果有:
a) 「COMMIT」,標識該事務已經或者最終會被提交
b) 「ABORT」,標識該事務最終會被回滾
c) 空,由於事務的狀態會在一個小時之後清楚,因此有以下兩種可能:
1) 一個小時之後查詢,標識事務狀態已經清除
2) 一個小時以內查詢,標識事務最終會被回滾
3) 運維命令:
xa recover:向後端SET發送xa recover命令,並進行匯總
xa lockwait:顯示當前分散式事務的等待關係(可以使用dot命令將輸出轉化為等待關係圖)
xa show:當前網關上正在運行的分散式事務
以Python為例,可以對轉賬業務進行如下編碼:
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)
# 為了安全起見,建議在這裡執行『SELECT gtid』獲取當前事務的id值,便於後續跟蹤事務的執行情況
#提交事務
cursor.execute("commit")
except pyMySQL.err.MySQLError as e:
# 發生故障,回滾事務
cursor.execute("rollback")
分散式事務的好處在於會大大降低應用開發難度,因為在某些不支持XA的資料庫中,需要業務系統通過特殊並且巧妙的設計,而非利用資料庫來解決事務中數據不一致等問題。這種對應用開發者的技術水平要求很高,越是複雜的業務系統,越會增加開發成本和技術門檻,這是業內大多數開發者面對分散式資料庫時,只能望而卻步的主要原因。
騰訊雲DCDB XA關鍵實現方案
1、DCDB架構介紹
騰訊雲DCDB整個集群架構簡圖如下圖,MySQL採用主從節點配置(也叫作主備)一套主從節點叫做SET,在每一個SET外配置網關(TProxy),形成一個物理分片(Shard)。
DCDB後端是MySQL(或其分支版本)資料庫,目前騰訊雲公有雲發布支持XA的版本是基於MySQL 5.7.17(percona分支)。
2、網關(TProxy)與XA
網關是用於接收請求並與後端MySQL建立連接的網路模塊。網關可以用兩種模式工作,一種稱為noshard,此模式下網關不處理/不解析SQL語句,透明轉發請求和應答。另一種模式稱為shard(分散式,即支持自動水平分表)模式下,TProxy會解析SQL並轉發到不同的數據分片。
在實現XA之前,網關不允許在一個事務中向多個SET發送DML語句。因為未實現二階段提交(2PC)時,事務採用一階段提交,如果分散式中某一個SET提交失敗了或回滾了,那麼這個分散式事務就處於不一致的狀態。
(網關的工作方式)
二階段提交中需要的事務管理器(TM)。為了解決容災、簡化架構,騰訊雲DCDB將TM實現在TProxy中,而DCDB的網關是一個無狀態的模塊,通過這一架構,DCDB XA可以支持:
1、分散式事務對業務透明,兼容單機事務語法(start transaction/commit/rollback/savepoint)。
2、每個網關都可以獨立接受和處理事務請求,且無需與其他網關進行協調節點故障不丟失事務。
3、允許顯式事務中多條語句分別發給多個分片。
4、網關無需持久狀態,無需容災,可以隨時經由調度集群退出或加入集群,且性能可以擴展。
5、支持autocommit下單條語句寫訪問多個分片等。
DCDB網關還允許以流式處理方式運行group by、order by,流式處理讓這類操作變得非常方式非常高效;網關還支持兩個Shard使用shardkey(分表鍵)做等值連接,以及使用shardkey的子查詢。
未來,騰訊雲還計劃支持分散式JOIN、Sparksql、二級分區等高級功能,兼容更多MySQL高級語法。
3、強同步與XA
由於騰訊雲DCDB默認採用強同步複製,即主從節點數據完全一致,因此XA事務也遵循強同步的邏輯,即需等待從機確認數據同步後,才給業務以應答(commit)。基於強同步,在以下兩種異常情況下,DCDB XA可輕鬆應對
1、主節點故障時,已確認事務數據不會丟失:主節點故障那麼擁有最新數據和binlog的從機就被選為主節點,這其中的數據也包括所有已經向用戶確認完成提交的事務的數據。
2、原主節點恢復後重新加入集群,未確認事務自動閃回:原主節點恢復重新接入集群,它將作為從機運行,此時他可能存留多餘的已提交事務(此時事務並未得到強同步同步確認,即原備機並沒有相關數據),那麼這些事務會被閃回。雖然這些事務可能已經在原主節點的MySQL內部完成提交,但由於強同步機制,他並不會向客戶端返回commit語句,這意味著仍被視為一個未完成的事務。因此,這些事務的閃回了也並沒有破壞資料庫的ACID屬性。這裡值得說的是,閃回flashback是基於binlog生成做逆操作,它與資料庫回滾並不同rollback,閃回可以做DDL操作。
騰訊雲DCDB的強同步為騰訊金融級資料庫自研的一項能力,性能比官方半同步大幅提高,幾乎等於非同步複製性能,騰訊雲DCDB在騰訊內部應用多年,未發生過一起因為主從切換、故障帶來的數據誤差。而且,從性能上,也撐住了騰訊公司各類大型運營活動如紅包、各類遊戲大型推廣等海量並發,其主要原因是強同步採用非同步提交/等待方式,且不佔用資料庫工作線程。
4、並發控制與隔離級別
為了達到數據一致性和性能的平衡,分散式事務的關鍵是資料庫隔離控制。XA的隔離級別最高可以達到serializable(完全串列化),該級別將不存在幻讀的問題,serializable級別可以通過設置SET global tx_isolation="serializable"來對DCDB所有物理分片(和其上承載的MySQL資料庫)進行設置。當然,也可以通過調整隔離級別以調整資料庫實例性能,理論上,Read Uncommitted性能最高,但可能存在臟讀、幻讀的情況。
隔離解別臟讀不可重複讀幻讀
Read UncommittedYYY
Read CommittedNYY
Repeatable(default)NNY
SerializableNNN
(ANSI/ISO定義的SQL-92標準定義的四種隔離級別)
5、分散式事務處理演算法
前面講到,騰訊雲DCDB的網關在shard模式下已經能夠解析SQL語句,騰訊雲在網關上實現TM以使得XA最具效率。為此,我們在網關中實現TM中的協調器(coordinator),並在網關中維護每個XA的狀態,記錄好每個XA寫入的SET,然後在提交階段做兩階段提交即可,大致流程如下:
1、網關在執行一個事務的insert/update/delete語句時,會記錄這個語句修改了哪個SET;
2、SET時會發送一個XA START在這個SET上面啟動事務分支;(註:XA事務開始時,並不確認事務將以哪種提交方式執行,因此總是以xa start來開啟一個事務)
3、檢測是否影響SET個數≤1,若是,則直接做一階段提交(xa commit one phase)。
4、影響SET個數≥2,則改為做兩階段提交
1)網關首先發送xa prepare 『gtid』 給參與的SET(大於等於2個SET)
2)SET接受到xa prepare應答ok(表示成功確認)
3)收到成功確認後,寫入XA對應的commit log,再發送xa commit 『gtid』參與SET。
4)如果有SET返回了錯誤,或者寫入commit log失敗,那麼網關發送 xa rollback 『gtid』 給相關SET,這樣這個全局事務就實現了回滾。
騰訊雲DCDB的commit log是在SET中存儲,這個步驟是批量完成的——網關後台線程會彙集正在提交的分散式事務然後在獨立的連接和事務中完成對每個SET的寫入,並且每個事務的commit log只寫入一個SET中,因而這個開銷並沒有顯著增加事務的提交耗時或者降低TPS。而且,依賴騰訊雲DCDB已有的強同步和容災特性,只要XA成功寫入了commit log,就意味著數據已經寫入從機。
雖然絕大多數的XA事務可以正常執行。但極少數的異常情況還是會影響整個集群穩定性,因此,騰訊雲設計了agent(監控模塊),在故障後繼續協助完成本地MySQL上面prepared事務的提交,即agent會解析commit log,並根據異常處理本地仍然處於prepared的事務數據;如果commit log上面沒有事務的提交決定的話,agent也會回滾超時未被提交的prepared本地事務。
雖然在MySQL 5.5、5.6等版本早已實現XA,但這兩個版本相對於5.7仍然有性能不足,因此騰訊雲目前只在公有雲上基於5.7.17支持XA版本。如今,騰訊雲在MySQL 、percona、MariaDB等分支中做了大量優化和相關bug修復(部分已經提交到社區修復patch或開源),未來騰訊雲還將繼續致力於新特性的開發和相關Bug的修復,為眾多有需要的企業,提供更好的分散式資料庫支持。


※數字技術時代的CIO:低成本低風險變化的掌控人
※Veeam跟隨虛擬巨頭,與Amazon達成合作關係
※西部數據公司確立下個收購目標——Tegile
※為什麼現代企業需提高企業敏捷性
※英特爾發布新的至強工作站晶元 冀博取虛擬現實和人工智慧開發人員的歡心
TAG:ZD至頂網 |
※分散式事務解決方案
※分散式一致性方案
※一文詳解分散式系統數據分片難題
※螞蟻金服大規模分散式事務實踐及四種分散式事務模式
※火龍果財經:能源行業現存問題——分散式解決方案
※分散式雲儲存
※分散式微服務架構體系詳解
※緩存分散式一致性難題,它解決了
※分散式事務資料庫評測體系研究與實踐
※分散式系統中常見技術解決的問題是什麼?
※分散式任務框架
※GTS來了!阿里微服務架構下的分散式事務解決方案
※開源分散式資料庫能否支撐銀行海量非結構化數據應用?
※分散式業務部署解決方案
※阿里大牛深入分析分散式柔性事務
※區塊鏈vs傳統資料庫:分散式運行有何優勢?
※安全問題頻發,DAEX想用分散式數字資產清算方案改變現狀
※響應式微服務架構-分散式系統設計原則
※分散式加密貨幣交換案例分析
※從架構特點到功能缺陷,重新認識分析型分散式資料庫