日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
怎樣徹底搞懂分布式事務XA模式

這期內(nèi)容當中小編將會給大家?guī)碛嘘P怎樣徹底搞懂分布式事務XA模式,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領域值得信任、有價值的長期合作伙伴,公司提供的服務項目有:申請域名、網(wǎng)頁空間、營銷軟件、網(wǎng)站建設、桃城網(wǎng)站維護、網(wǎng)站推廣。

XA 協(xié)議是由 X/Open 組織提出的分布式事務處理規(guī)范,主要定義了事務管理器 TM 和局部資源管理器 RM 之間的接口。目前主流的數(shù)據(jù)庫,比如 oracle、DB2 都是支持 XA 協(xié)議的。

MySQL 從 5.0 版本開始,innoDB 存儲引擎已經(jīng)支持 XA 協(xié)議,今天的源碼介紹實驗環(huán)境使用的是 mysql 數(shù)據(jù)庫。

兩階段提交

分布式事務的兩階段提交是把整個事務提交分為 prepare 和 commit 兩個階段。以電商系統(tǒng)為例,分布式系統(tǒng)中有訂單、賬戶和庫存三個服務,如下圖:

怎樣徹底搞懂分布式事務XA模式

第一階段,事務協(xié)調(diào)者向事務參與者發(fā)送 prepare 請求,事務參與者收到請求后,如果可以提交事務,回復 yes,否則回復 no。

第二階段,如果所有事務參與者都回復了 yes,事務協(xié)調(diào)者向所有事務參與者發(fā)送 commit 請求,否則發(fā)送 rollback 請求。

兩階段提交存在三個問題:

  • 同步阻塞,本地事務在 prepare 階段鎖定資源,如果有其他事務也要修改 xiaoming 這個賬戶,就必須等待前面的事務完成。這樣就造成了系統(tǒng)性能下降。

  • 協(xié)調(diào)節(jié)點單點故障,如果第一個階段 prepare 成功了,但是第二個階段協(xié)調(diào)節(jié)點發(fā)出 commit 指令之前宕機了,所有服務的數(shù)據(jù)資源處于鎖定狀態(tài),事務將無限期地等待。

  • 數(shù)據(jù)不一致,如果第一階段 prepare 成功了,但是第二階段協(xié)調(diào)節(jié)點向某個節(jié)點發(fā)送 commit 命令時失敗,就會導致數(shù)據(jù)不一致。

三階段提交

為了解決兩階段提交的問題,三階段提交做了改進:

  • 在協(xié)調(diào)節(jié)點和事務參與者都引入了超時機制。

  • 第一階段的 prepare 階段分成了兩步,canCommi 和 preCommit。

如下圖:

怎樣徹底搞懂分布式事務XA模式

引入 preCommit 階段后,協(xié)調(diào)節(jié)點會在 commit 之前再次檢查各個事務參與者的狀態(tài),保證它們的狀態(tài)是一致的。但是也存在問題,那就是如果第三階段發(fā)出 rollback 請求,有的節(jié)點沒有收到,那沒有收到的節(jié)點會在超時之后進行提交,造成數(shù)據(jù)不一致。

XA 事務語法介紹

xa 事務的語法如下:

  1. 三階段的第一階段:開啟 xa 事務,這里 xid 為全局事務 id:

XA {START|BEGIN} xid [JOIN|RESUME]

結束 xa 事務:

XA END xid [SUSPEND [FOR MIGRATE]]
  1. 三階段的第二階段,即 prepare:

XA PREPARE xid
  1. 三階段的第三階段,即 commit/rollback:

XA COMMIT xid [ONE PHASE]
XA ROLLBACK xid
  1. 查看處于 PREPARE 階段的所有事務:

XA RECOVER XA RECOVER [CONVERT XID]

seata XA 簡介

seata 是阿里推出的一款開源分布式事務解決方案,目前有 AT、TCC、SAGA、XA 四種模式。

seata 的 XA 模式是利用分支事務中數(shù)據(jù)庫對 XA 協(xié)議的支持來實現(xiàn)的。我們看一下 seata 官網(wǎng)的介紹:[1]

怎樣徹底搞懂分布式事務XA模式

從上面的圖可以看到,seata XA 模式的流程跟其他模式一樣:

  1. TM 開啟全局事務

  2. RM 向 TC 注冊分支事務

  3. RM 向 TC 報告分支事務狀態(tài)

  4. TC 向 RM 發(fā)送 commit/rollback 請求

  5. TM 結束全局事務

這里介紹一下 RM 客戶端初始化關聯(lián)的 UML 類圖:[2]

怎樣徹底搞懂分布式事務XA模式

這個圖中有一個類是 AbstractNettyRemotingClient,這個類的內(nèi)部類 ClientHandler 來處理 TC 發(fā)來的請求并委托給父類 AbstractNettyRemoting 的 processMessage 方法來處理。processMessage 方法調(diào)用 RmBranchCommitProcessor 類的 process 方法。

需要注意的是,「seata 的 xa 模式對傳統(tǒng)的三階段提交做了優(yōu)化,改成了兩階段提交」:

  • 第一階段首執(zhí)行 XA 開啟、執(zhí)行 sql、XA 結束三個步驟,之后直接執(zhí)行 XA prepare。

  • 第二階段執(zhí)行 XA commit/rollback。

mysql 目前是支持 seata xa 模式的兩階段優(yōu)化的。

「但是這個優(yōu)化對 oracle 不支持,因為 oracle 實現(xiàn)的是標準的 xa 協(xié)議,即 xa end 后,協(xié)調(diào)節(jié)點向事務參與者統(tǒng)一發(fā)送 prepare,最后再發(fā)送 commit/rollback。這也導致了 seata 的 xa 模式對 oracle 支持不太好?!?/strong>

seata XA 源碼

seata 中的 XA 模式是使用數(shù)據(jù)源代理來實現(xiàn)的,需要手動配置數(shù)據(jù)源代理,代碼如下:

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
    return new DruidDataSource();
}

@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
    return new DataSourceProxyXA(druidDataSource);
}
  • 也可以根據(jù)普通 DataSource 來創(chuàng)建 XAConnection,但是這種方式有兼容性問題(比如 oracle),所以 seata 使用了開發(fā)者自己配置 XADataSource。

  • seata 提供的 XA 數(shù)據(jù)源代理,要求代碼框架中必須使用 druid 連接池。

1. XA 第一階段

當 RM 收到 DML 請求后,seata 會使用 ExecuteTemplateXA來執(zhí)行,執(zhí)行方法 execute 中有一個地方很關鍵,就是把 autocommit 屬性改為了 false,而 mysql 默認 autocommit 是 true。事務提交之后,還要把 autocommit 改回默認。

下面我們看一下 XA 第一階段提交的主要代碼。

1)開啟 XA

上面代碼標注[1]處,調(diào)用了 ConnectionProxyXA 類的 setAutoCommit 方法,這個方法的源代碼中,XA start 主要做了三件事:

  • 向 TC 注冊分支事務

  • 調(diào)用數(shù)據(jù)源的 XA Start

xaResource.start(this.xaBranchXid, XAResource.TMNOFLAGS);
  • 把 xaActive 設置為 true

RM 并沒有直接使用 TC 返回的 branchId 作為 xa 數(shù)據(jù)源的 branchId,而是使用全局事務 id(xid) 和 branchId 重新構建了一個。

2)執(zhí)行 sql

調(diào)用 PreparedStatementProxyXA 的 execute 執(zhí)行 sql。

3)XA end/prepare

public void commit() throws SQLException {
    //省略部分源代碼
    try {
        // XA End: Success
        xaResource.end(xaBranchXid, XAResource.TMSUCCESS);
        // XA Prepare
        xaResource.prepare(xaBranchXid);
        // Keep the Connection if necessary
        keepIfNecessary();
    } catch (XAException xe) {
        try {
            // Branch Report to TC: Failed
            DefaultResourceManager.get().branchReport(BranchType.XA, xid, xaBranchXid.getBranchId(),
                BranchStatus.PhaseOne_Failed, null);
        } catch (TransactionException te) {
            //這兒只打印了一個warn級別的日志
        }
        throw new SQLException(
            "Failed to end(TMSUCCESS)/prepare xa branch on " + xid + "-" + xaBranchXid.getBranchId() + " since " + xe
                .getMessage(), xe);
    } finally {
        cleanXABranchContext();
    }
}

從這個源碼我們看到,commit 主要做了三件事:

  • 調(diào)用數(shù)據(jù)源的 XA end

  • 調(diào)用數(shù)據(jù)源的 XA prepare

  • 向 TC 報告分支事務狀態(tài)

到這里我們就可以看到,seata 把 xa 協(xié)議的前兩個階段合成了一個階段。

2. XA commit

這里的調(diào)用關系用一個時序圖來表示:

怎樣徹底搞懂分布式事務XA模式

看一下 RmBranchCommitProcessor 類的 process 方法,代碼如下:

@Override
public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception {
    String remoteAddress = NetUtil.toStringAddress(ctx.channel().remoteAddress());
    Object msg = rpcMessage.getBody();
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("rm client handle branch commit process:" + msg);
    }
    handleBranchCommit(rpcMessage, remoteAddress, (BranchCommitRequest) msg);
}

從調(diào)用關系時序圖可以看出,上面的 handleBranchCommit 方法最終調(diào)用了 AbstractRMHandler 的 handle 方法,最后通過 branchCommit 方法調(diào)用了 ResourceManagerXA 類的 finishBranch 方法。 ResourceManagerXA 類是 XA 模式的資源管理器,看下面這個類圖,也就是 seata 中資源管理器(RM)的 UML 類圖:

怎樣徹底搞懂分布式事務XA模式

上面的 finishBranch 方法調(diào)用了 connectionProxyXA.xaCommit 方法,我們最后看一下 xaCommit 方法:

public void xaCommit(String xid, long branchId, String applicationData) throws XAException {
    XAXid xaXid = XAXidBuilder.build(xid, branchId);
 //因為使用mysql,這里xaResource是MysqlXAConnection
    xaResource.commit(xaXid, false);
    releaseIfNecessary();
}

上面調(diào)用了數(shù)據(jù)源的 commit 方法,提交了 RM 分支事務。

到這里,整個 RM 分支事務就結束了。Rollback 的代碼邏輯跟 commit 類似。

最后要說明的是,上面的 xaResource,是 mysql-connector-java.jar 包中的 MysqlXAConnection 類實例,它封裝了 mysql 提供的 XA 協(xié)議接口。

seata 中 XA 模式的實現(xiàn)是使用數(shù)據(jù)源代理完成的,底層使用了數(shù)據(jù)庫對 XA 協(xié)議的原生支持。

mysql 的 java 驅(qū)動庫中,MysqlXAConnection 類封裝類 XA 協(xié)議的底層接口供外部調(diào)用。

跟 TCC 和 SAGA 模式需要在業(yè)務代碼中實現(xiàn) prepare/commit/rollback 邏輯相比,XA 模式對業(yè)務代碼無侵入。

上述就是小編為大家分享的怎樣徹底搞懂分布式事務XA模式了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


本文標題:怎樣徹底搞懂分布式事務XA模式
鏈接地址:http://www.dlmjj.cn/article/iiggid.html