DRDS事務模型
更新時間 2024-03-12 20:32:47
最近更新時間: 2024-03-12 20:32:47
分享文章
本文主要介紹DRDS的分布式事務。
分布式事務介紹
使用分布式關系型數據庫后,一個事務如果涉及到多個物理數據庫節點操作,可能會出現部分物理節點處理成功、部分失敗的中間狀態。按照傳統的數據庫操作方式無法保障數據的一致性及可用性,這就是在分布式數據庫中需要解決的分布式事務問題。
分布式事務解決方案
這里主要列出由DRDS提供的幾種分布式事務解決方案。
補償型事務方案
基本原理
- 應用發起的事務涉及多個后端數據庫節點的修改。
- 在COMMIT前,DRDS會保存整個分布式事務中涉及的所有SQL。
- 當COMMIT部分出錯的時候,DRDS會給應用返回處理成功。
- DRDS記錄事務的出錯節點,讓事務補償器進行事務補償。
- DRDS事務補償器自動對事務中出錯節點進行事務補償,記錄補償結果。
- 應用在進入下一環節時,需要檢查以上數據是否完整。
基本流程
- 啟動分布式事務:dt start [tab]; 會返回事務ID。
- 執行SQL:如果SQL涉及到的表在某些節點中處于事務補償狀態,這些表在該節點中的數據不能被訪問, 因此SQL執行的時候會被鎖住或者返回錯誤。
- commit分布式事務:commit的時候會先執行次要節點,然后再執行主要節點。主要節點是最后一條SQL對應的唯一節點。
- 檢查是否有wanrings返回:show warnings。
- 如果有warnings返回,使用事務ID,查詢補償是否完成:dt status tid。
補償示例
public void transferOwn throws Exception {
public static final String name = "com.mysql.jdbc.Driver";
public static final String user = "drdsUser";
public static final String password = "*********";
Class. forName (name);//指定連接類型
String url = ”ip:port”;
String schema = "schemaName";
Connection c = DriverManager.getConnection (String. format( "jdbc:mysql://%s/ %s ?user=%s&password=%s&useUnicode=true&characterEncoding=utf-8",
url, schema, userName, password));
c.setAutoCommit (false);
Statement s = c.createStatement();
//開啟分布式事務
s.execute ("dt start");
//執行業務邏輯
s. execute ("xxx;");
c.commit();
}
基于XA的事務方案
XA的定義
XA是X/Open DTP定義的兩階段提交協議,是交易中間件與數據庫之間的接口規范(即接口函數),交易中間件用它來通知數據庫事務的開始、結束以及提交、回滾等,提交或回滾事務必須產生一致的結果(全部提交或全部回滾)。XA接口函數由數據庫廠商提供。通常情況下,交易中間件與數據庫通過XA接口規范,使用兩階段提交來完成一個全局事務,XA規范的基礎是兩階段提交協議。
原理
分布式XA事務利用物理數據庫提供了對XA事務的支持,實現跨數據庫事務的一致性。為保證事務的原子性(Atomicity)和一致性(Consistency),使用二階段提交,將事務提交分成PREPARE和COMMIT兩個階段:
- PREPARE階段中,數據節點準備好所有事務提交所需的資源(例如加鎖、寫日志等);這個階段保證了事務數據的高可用性:數據庫掛了恢復后,也會恢復還沒提交的PREPARE事務。
- COMMIT階段中,各個數據節點才真正提交事務。
當用戶進行一個分布式XA事務時,DRDS作為事務管理器角色。DRDS會屏蔽XA事務實現的細節。對用戶而言,跟普通事務是一樣的流程。
XA事務流程
- XA事務開啟:執行UDAL XA START。這時DRDS會返回這個XA事務的XID。
- XA事務執行:執行各種語句。這時DRDS跟普通事務一樣的處理。
- XA事務提交 : 執行COMMIT或ROLLBACK。 DRDS首先等待所有數據節點(MySQL服務器)PREPARE成功,之后再向各個數據節點發送COMMIT請求。
XA示例
以下是業務連接DRDS的事務示例。
public static final String url = "jdbc:mysql://127.0.0.1/employee";
public static final String name = "com.mysql.jdbc.Driver";
public static final String user = "drdsUser";
public static final String password = "*********";
Class.forName (name);//指定連接類型
try (Connection conn = DriverManager. getConnection (drdsUrl, drdsUser, password)) {
//開啟事務,獲取DRDS事務全局唯一的xid
try (Resul tSet set = statement. executeQuery(”UDAL XA START”)){
while (set.next()) {
xid=set.getString(1);
}
}
st. execute("insert into custamr values (id, name) (1,"test1") ;");//分片1執行語句
st. execute("insert into custamr values (id, name) (2,"test1") ;");//分片2執行語句
conn.commit() //事務提交
}catch (SQLException e) {
conn. rollback();
}
建議
解決分布式事務的推薦方法就是盡量規避分布式事務,事務邊界越大(或者單個SQL所執行的數據分片數),那么系統的鎖沖突概率越高,系統越難以擴展,性能越低。因此,若想將系統做到很好的擴展性,那么一個重要的原則就是想辦法劃小事務邊界,并盡可能讓事務的邊界限制在單臺機器內。