<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go開源說第十七期 分布式事務(wù)DTM

          共 4611字,需瀏覽 10分鐘

           ·

          2021-10-13 02:52

          大家好,很高興到“Go開源說”跟大家分享DTM,我是葉東富,DTM作者,github:https://github.com/yedf

          內(nèi)容提綱

          本次分享分為以下四個(gè)部分:

          1. DTM是什么

          2. 產(chǎn)生的背景

          3. 可以解決什么問題

          4. 發(fā)展現(xiàn)狀與未來

          DTM是什么

          我們按照開源項(xiàng)目的習(xí)慣,以一個(gè)類似Quick Start的例子來說明:

          一個(gè)例子

          業(yè)務(wù)場景:A跨行轉(zhuǎn)給B 30元,A、B分屬不同銀行

          需求要點(diǎn):

          • 需要保證A-30和B+30,都成功,或都失敗

          • 中間任何一個(gè)地方發(fā)生故障,不能影響最終的數(shù)據(jù)一致性

          • 因數(shù)據(jù)保存在多個(gè)數(shù)據(jù)庫實(shí)例,無法通過本地事務(wù)解決

          解決方案DTM:A Distributed Transaction Manager

            req := &gin.H{"amount": 30} // 微服務(wù)的載荷  // DtmServer為DTM服務(wù)的地址  saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).    // 添加一個(gè)TransOut的子事務(wù),正向操作為url: qsBusi+"/TransOut", 逆向操作為url: qsBusi+"/TransOutCompensate"    Add(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", req).    // 添加一個(gè)TransIn的子事務(wù),正向操作為url: qsBusi+"/TransIn", 逆向操作為url: qsBusi+"/TransInCompensate"    Add(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", req)  // 提交saga事務(wù),dtm會(huì)完成所有的子事務(wù)/回滾所有的子事務(wù)  err := saga.Submit()

          在這個(gè)例子中:

          1. 定義了一個(gè)Saga事務(wù)

          2. Saga事務(wù)中的第一個(gè)子事務(wù)TransOut負(fù)責(zé)扣減A的余額

          3. Saga事務(wù)中的第一個(gè)子事務(wù)TransIn負(fù)責(zé)增加B的余額

          4. 完成了Saga事務(wù)定義之后,將事務(wù)提交給DTM

          5. DTM將按順序完成各項(xiàng)子事務(wù)

          6. 如果中間出現(xiàn)臨時(shí)的網(wǎng)絡(luò)錯(cuò)誤,DTM會(huì)負(fù)責(zé)重試

          7. 如果業(yè)務(wù)返回失敗,DTM會(huì)調(diào)用子事務(wù)的補(bǔ)償操作,保證最終數(shù)據(jù)一致性

          跨數(shù)據(jù)源、跨服務(wù)的數(shù)據(jù)一致性

          DTM是跨數(shù)據(jù)源、跨服務(wù)的數(shù)據(jù)一致性解決方案,他又可以分為以下三類:跨數(shù)據(jù)庫、跨服務(wù)、混合

          易混淆的分布式數(shù)據(jù)庫事務(wù)

          現(xiàn)在涌現(xiàn)出構(gòu)建在分布式系統(tǒng)上的數(shù)據(jù)庫--NewSQL,能夠隨著分布式系統(tǒng)的動(dòng)態(tài)擴(kuò)容而大幅提高系統(tǒng)的服務(wù)能力,例如谷歌的Spanner、國產(chǎn)的TiDB。NewSQL的事務(wù)是在分布式系統(tǒng)上構(gòu)建的,也被稱之為分布式事務(wù),但是與我們在前面介紹的分布式事務(wù)在解決問題類型不同,所使用的核心技術(shù)也不同。

          NewSQL事務(wù)主要解決的是數(shù)據(jù)庫擴(kuò)展到多Host下的ACID,聚焦在數(shù)據(jù)庫系統(tǒng)層面,而DTM聚焦在應(yīng)用層和多數(shù)據(jù)源之間的數(shù)據(jù)一致性。

          產(chǎn)生的背景

          隨著我們公司業(yè)務(wù)的發(fā)展,交易系統(tǒng)越來越復(fù)雜,交易并發(fā)也越來越高。原先一個(gè)交易是放在一個(gè)本地事務(wù)里完成,由數(shù)據(jù)庫來保證ACID。這種架構(gòu),一方面要求把所有訂單交易的操作在一個(gè)服務(wù),導(dǎo)致無法微服務(wù)化,這樣就會(huì)把所有訂單涉及的子系統(tǒng)耦合進(jìn)訂單中,復(fù)雜度很高;另一方面,訂單修改庫存到訂單提交的這段時(shí)間里,庫存是被鎖定的,購買同一個(gè)商品的所有訂單會(huì)因?yàn)榭蹘齑娴男墟i導(dǎo)致串行,并發(fā)度低。

          我們系統(tǒng)采用的語言棧是Node,調(diào)研之后,決定之后采用Go作為主棧。如果把交易系統(tǒng)全部用Go改寫之后再上線,周期十分漫長,對業(yè)務(wù)非常不友好。我們需要做漸進(jìn)式的改造,需要分布式事務(wù)支持一部分服務(wù)Go編寫,一部分服務(wù)Node編寫,然后把相關(guān)服務(wù)組合成一個(gè)全局的分布式事務(wù)。

          當(dāng)前可選方案

          我們調(diào)研了當(dāng)時(shí)市面上的方案,最成熟、應(yīng)用最廣泛的是阿里開源的Seata,它是Java語言開發(fā)的,如果我們選用這個(gè)方案的話,需要把訂單相關(guān)的系統(tǒng),全部改造成Java,工作量巨大,預(yù)計(jì)要20人月以上。還有其他方案,例如hmily、tcc-transaction、ByteTCC,這些都是Java的方案,工作量都接近。

          其他語言的分布式事務(wù)方案,沒有看到成熟可用的,Go、PHP、Python、Node等語言搜索了一個(gè)遍,都未發(fā)現(xiàn)好的方案。

          加上前面我們希望要一個(gè)漸進(jìn)式的方案,需要支持多語言的子服務(wù)組合成一個(gè)全局事務(wù),那么市面上的方案就更不可能了。綜合評估下來,我們決定自己開發(fā)

          DTM架構(gòu)

          我們開發(fā)的DTM架構(gòu)如下:


          圖中左上角的Go客戶端SDK等,都是輕量級的SDK,大約幾十到幾百行代碼,新增一門語言支持非常容易。DTM服務(wù)器采用云原生友好的無狀態(tài)服務(wù),可以非常方便的動(dòng)態(tài)擴(kuò)容、做高可用,數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫,和現(xiàn)在絕大多數(shù)公司的存儲(chǔ)架構(gòu)一致。

          我們支持了類似如下的多語言,能夠采用各種語言編寫子服務(wù),最終組合成一個(gè)全局事務(wù):

          可以解決什么問題

          DTM提供了跨數(shù)據(jù)源分布式事務(wù)的一站式解決方案,支持的事務(wù)模式包括:可靠消息、事務(wù)消息、TCC、SAGA、XA。而在這些事務(wù)模式中,有一個(gè)難點(diǎn)問題是如果中間發(fā)生異常,導(dǎo)致子事務(wù)亂序要怎么解決。

          異常

          典型的異常分為三類,:

          • 空補(bǔ)償:可能出現(xiàn)回滾請求在正向操作前到達(dá),此時(shí)需忽略

          • 懸掛:可能出現(xiàn)回滾后,再收到正向操作,此時(shí)需忽略

          • 冪等:可能出現(xiàn)重復(fù)請求,需要允許操作重試,不影響結(jié)果

          通俗一點(diǎn)說,轉(zhuǎn)賬這類的分布式事務(wù),可能會(huì)出現(xiàn)服務(wù)先收到撤銷轉(zhuǎn)賬的請求,然后再收到轉(zhuǎn)賬的請求。下面是一個(gè)時(shí)序圖,很好的演示了異常的情況:

          其中:

          • 5 Cancel在Try之前被調(diào)用,是空補(bǔ)償

          • 7 Cancel和5的重復(fù),是重復(fù)請求

          • 8 Try在Cancel之后執(zhí)行,是懸掛操作

          目前沒有看到哪個(gè)項(xiàng)目在這方面有成熟好用的解決方案,包括Seata,都要求業(yè)務(wù)層面直接處理這類問題。業(yè)務(wù)直接處理這類問題,面臨大量邏輯判斷,復(fù)雜易出錯(cuò),需要花費(fèi)大量的時(shí)間進(jìn)行調(diào)試測試,而且由于懸掛這樣的問題難以模擬,可能要線上跑一段時(shí)間后才會(huì)出現(xiàn)。業(yè)務(wù)對于這樣的情況只能表示很無奈,很頭疼。

          子事務(wù)屏障

          DTM首創(chuàng)了子事務(wù)屏障,系統(tǒng)性的解決了上述的異常問題,效果示意圖如下:

          所有這些請求,到了子事務(wù)屏障后:不正常的請求,會(huì)被過濾;正常請求,通過屏障。開發(fā)者使用子事務(wù)屏障之后,前面所說的各種異常全部被妥善處理,業(yè)務(wù)開發(fā)人員只需要關(guān)注實(shí)際的業(yè)務(wù)邏輯,負(fù)擔(dān)大大降低。
          子事務(wù)屏障提供了方法BranchBarrier.Call,方法的原型為:

          func (bb *BranchBarrier) Call(db *sql.DB, busiCall BusiFunc) error

          業(yè)務(wù)開發(fā)人員,在busiCall里面編寫自己的相關(guān)邏輯,調(diào)用BranchBarrier.Call。BranchBarrier.Call保證,在空回滾、懸掛等場景下,busiCall不會(huì)被調(diào)用;在業(yè)務(wù)被重復(fù)調(diào)用時(shí),有冪等控制,保證只被提交一次。

          子事務(wù)屏障會(huì)管理TCC、SAGA、事務(wù)消息等,也可以擴(kuò)展到其他領(lǐng)域

          有了子事務(wù)屏障的幫助,分布式事務(wù)的使用門檻大大降低,原先需要架構(gòu)師才能勝任的工作,現(xiàn)在只需要普通開發(fā)人員就可以完成。未來DTM有可能成為推進(jìn)微服務(wù)化的核心組件。

          說完了所有事務(wù)模式共同的問題和解決方案后,我們下面看一下DTM對各個(gè)事務(wù)模式的支持:

          可靠消息、事務(wù)消息

          這兩種事務(wù)模式保證消息至少被成功消費(fèi)一次(或者說相關(guān)服務(wù)的執(zhí)行最少成功一次),保證多個(gè)微服務(wù)被原子執(zhí)行,它適合不需要回滾的業(yè)務(wù)場景。例如:

          • 點(diǎn)擊按鈕,領(lǐng)取優(yōu)惠券+會(huì)員,領(lǐng)優(yōu)惠券+會(huì)員不需要回滾,這種情況適合可靠消息

          • 注冊成功后,領(lǐng)取優(yōu)惠券+會(huì)員,這種情況適合事務(wù)消息。

          第二種情況和第一種對比,差別主要是只有注冊成功,才領(lǐng)取,如果注冊失敗,不可以領(lǐng)取,這種情況適合事務(wù)消息

          DTM的支持如下:


          如果是事務(wù)消息,那么在本地事務(wù)提交之前調(diào)用Prepare,提交之后調(diào)用Commit。如果沒有本地事務(wù),其實(shí)就是可靠消息,忽略Prepare調(diào)用即可。

          XA

          XA是標(biāo)準(zhǔn)二階段提交,一階段Prepare,二階段Commit/Rollback。一階段的所有Prepare成功,則Commit,否則Rollback。從修改數(shù)據(jù)開始,到Commit/Rollback結(jié)束,鎖定數(shù)據(jù)長,并發(fā)度較低。

          這種事務(wù)模式適合并發(fā)不高的訂單轉(zhuǎn)賬等各項(xiàng)業(yè)務(wù)。

          DTM的支持如下:

          TCC

          TCC的每個(gè)子事務(wù)有兩個(gè)階段:一階段Try;二階段Confirm/Cancel;Try中進(jìn)行資源預(yù)留,例如凍結(jié)資金;一階段如果全部成功,則Confirm,例如進(jìn)行余額扣減,解凍資金;一階段如果有一個(gè)子事務(wù)出現(xiàn)失敗,則Cancel,例如解凍資金;

          TCC模式不長期鎖數(shù)據(jù),并發(fā)高。常用于支付、訂單類業(yè)務(wù)的拆分。

          DTM的支持如下:

          SAGA

          SAGA每個(gè)子事務(wù)有正向分支和補(bǔ)償分支,它在正向分支中直接修改數(shù)據(jù),出錯(cuò)則補(bǔ)償所有修改過的數(shù)據(jù)。

          SAGA比TCC少一個(gè)分支,一致性比TCC弱。適用于積分換禮品等不涉及資金業(yè)務(wù);也適用于對接較多第三方的長事務(wù)。

          DTM的支持如下:

          未支持的模式AT

          AT為SEATA和部分其他的框架提供的事務(wù)模式,各方面特性類似于XA,性能比XA高,但低于其他模式。

          這種模式的使用需要小心避免臟回滾,假如T1修改Row1,然后Row1被T2直接修改,接下來T1回滾,此時(shí)出現(xiàn)臟回滾,需要手動(dòng)處理。Seata給出避免這種臟回滾的辦法是,所有要修改Row1的訪問,都必須使用Seata中的Transaction注解,這個(gè)要求在多團(tuán)隊(duì)協(xié)作,新舊系統(tǒng)兼容上難以保證。

          因?yàn)榕K回滾以及類似XA的特性,DTM支持了XA,并未支持AT模式,預(yù)計(jì)近期也不會(huì)支持。

          DTM支持的其他場景

          DTM還有一些其他典型的適用場景,例如:多個(gè)應(yīng)用間的對賬系統(tǒng)、發(fā)布文章后更新各類統(tǒng)計(jì)信息等

          單服務(wù)多數(shù)據(jù)源

          DTM對單服務(wù)多數(shù)據(jù)源的支持非常優(yōu)雅,只需要將每個(gè)數(shù)據(jù)源的修改用一個(gè)子事務(wù)屏障包裝起來即可。如圖所示:

          發(fā)展現(xiàn)狀與未來

          已完成的特性

          • 從生產(chǎn)系統(tǒng)提煉而來,已接入三家

          • 中英文文檔

          • HTTP/gRPC支持

          • 測試覆蓋95%以上

          • Promethues監(jiān)控

          • 完善的CI/CD

          • 支持的語言包括Go、Python、PHP、Node、Java、C#等

          • 完整的線上部署文檔,含直接部署、Docker、K8S

          行業(yè)影響

          干貨推廣文《分布式事務(wù)最經(jīng)典的其中解決方案》被大量的自媒體自發(fā)轉(zhuǎn)載(不是主動(dòng)投稿),大約有幾十個(gè)公眾號,多個(gè)自媒體平臺(tái)(包括脈脈,微博等)。該文章兩個(gè)月時(shí)間就排到谷歌搜索“分布式事務(wù)"結(jié)果第二。

          DTM在Github上面的star增長迅速,受到了很大的關(guān)注



          下圖是DTM和Seata在重要特性上的對比:

          可以看到DTM在各項(xiàng)重要特性上不輸于,甚至優(yōu)于第一名,未來的發(fā)展?jié)摿艽?,他的目?biāo)是成為云原生架構(gòu)的核心組件

          結(jié)束

          我們的項(xiàng)目地址是:https://github.com/yedf/dtm

          文檔是:https://dtm.pub

          大家還可以通過掃碼進(jìn)群,一起交流~



          瀏覽 210
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天爽夜爽 | AAAAAAA级片 | 成人做爱网址 | 天天超碰| 日韩电影久久 |