<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>

          7種分布式事務的解決方案,一次講給你聽

          共 5437字,需瀏覽 11分鐘

           ·

          2021-03-06 04:18

          本文約5300字,閱讀時長「5分鐘」

          什么是分布式事務

          分布式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器「分別位于不同的分布式系統(tǒng)的不同節(jié)點之上」。

          一個大的操作由N多的小的操作共同完成。而這些小的操作又分布在不同的服務上。針對于這些操作,「要么全部成功執(zhí)行,要么全部不執(zhí)行」。

          為什么會有分布式事務?

          舉個例子:

          轉(zhuǎn)賬是最經(jīng)典的分布式事務場景,假設用戶 A 使用銀行 app 發(fā)起一筆跨行轉(zhuǎn)賬給用戶 B,銀行系統(tǒng)首先扣掉用戶 A 的錢,然后增加用戶 B 賬戶中的余額。

          如果其中某個步驟失敗,此時就有可能會出現(xiàn) 2 種「異?!?/strong>情況:

          • 1.用戶 A 的賬戶扣款成功,用戶 B 賬戶余額增加失敗
          • 2.用戶 A 賬戶扣款失敗,用戶 B 賬戶余額增加成功。

          對于銀行系統(tǒng)來說,以上 2 種情況都是「不允許發(fā)生」,此時就需要事務來保證轉(zhuǎn)賬操作的成功。

          「單體應用」中,我們只需要貼上@Transactional注解就可以開啟事務來保證整個操作的「原子性」。

          但是看似以上簡單的操作,在實際的應用架構(gòu)中,不可能是單體的服務,我們會把這一系列操作交給「N個服務」去完成,也就是拆分成為「分布式微服務架構(gòu)」。

          比如下訂單服務,扣庫存服務等等,必須要「保證不同服務狀態(tài)結(jié)果的一致性」,于是就出現(xiàn)了分布式事務。

          分布式理論

          CAP定理

          在一個分布式系統(tǒng)中,以下三點特性無法同時滿足,「魚與熊掌不可兼得」

          一致性(C):
          在分布式系統(tǒng)中的所有數(shù)據(jù)備份,「在同一時刻是否擁有同樣的值」。(等同于所有節(jié)點訪問同一份最新的數(shù)據(jù)副本)

          可用性(A):
          在集群中一部分節(jié)點「故障」后,集群整體「是否還能響應」客戶端的讀寫請求。(對數(shù)據(jù)更新具備高可用性)

          分區(qū)容錯性(P):
          即使出現(xiàn)「單個組件無法可用,操作依然可以完成」

          具體地講在分布式系統(tǒng)中,在任何數(shù)據(jù)庫設計中,一個Web應用「至多只能同時支持上面的兩個屬性」。顯然,任何橫向擴展策略都要依賴于數(shù)據(jù)分區(qū)。因此,設計人員必須在一致性與可用性之間做出選擇。

          BASE理論

          在分布式系統(tǒng)中,我們往往追求的是可用性,它的重要程序比一致性要高,那么如何實現(xiàn)高可用性呢?

          前人已經(jīng)給我們提出來了另外一個理論,就是BASE理論,它是用來對CAP定理進行進一步擴充的。BASE理論指的是:

          • 「Basically Available(基本可用)」
          • 「Soft state(軟狀態(tài))」
          • 「Eventually consistent(最終一致性)」

          BASE理論是對CAP中的一致性和可用性進行一個權(quán)衡的結(jié)果,理論的核心思想就是:我們無法做到強一致,但每個應用都可以根據(jù)自身的業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性(Eventual consistency)。

          分布式事務解決方案

          兩階段提交(2PC)

          熟悉mysql的同學對兩階段提交應該頗為熟悉,mysql的事務就是通過「日志系統(tǒng)」來完成兩階段提交的。

          兩階段協(xié)議可以用于單機集中式系統(tǒng),由事務管理器協(xié)調(diào)多個資源管理器;也可以用于分布式系統(tǒng),「由一個全局的事務管理器協(xié)調(diào)各個子系統(tǒng)的局部事務管理器完成兩階段提交」。

          這個協(xié)議有「兩個角色」,

          A節(jié)點是事務的協(xié)調(diào)者,B和C是事務的參與者。

          事務的提交分成兩個階段

          第一個階段是「投票階段」

          • 1.協(xié)調(diào)者首先將命令「寫入日志」
          • 2. 「發(fā)一個prepare命令」給B和C節(jié)點這兩個參與者
          • 3.B和C收到消息后,根據(jù)自己的實際情況,「判斷自己的實際情況是否可以提交」
          • 4.將處理結(jié)果「記錄到日志」系統(tǒng)
          • 5.將結(jié)果「返回」給協(xié)調(diào)者

          第二個階段是「決定階段」

          當A節(jié)點收到B和C參與者所有的確認消息后

          • 「判斷」所有協(xié)調(diào)者「是否都可以提交」
            • 如果可以則「寫入日志」并且發(fā)起commit命令
            • 有一個不可以則「寫入日志」并且發(fā)起abort命令
          • 參與者收到協(xié)調(diào)者發(fā)起的命令,「執(zhí)行命令」
          • 將執(zhí)行命令及結(jié)果「寫入日志」
          • 「返回結(jié)果」給協(xié)調(diào)者

          可能會存在哪些問題?

          • 「單點故障」:一旦事務管理器出現(xiàn)故障,整個系統(tǒng)不可用

          • 「數(shù)據(jù)不一致」:在階段二,如果事務管理器只發(fā)送了部分 commit 消息,此時網(wǎng)絡發(fā)生異常,那么只有部分參與者接收到 commit 消息,也就是說只有部分參與者提交了事務,使得系統(tǒng)數(shù)據(jù)不一致。

          • 「響應時間較長」:整個消息鏈路是串行的,要等待響應結(jié)果,不適合高并發(fā)的場景

          • 「不確定性」:當事務管理器發(fā)送 commit 之后,并且此時只有一個參與者收到了 commit,那么當該參與者與事務管理器同時宕機之后,重新選舉的事務管理器無法確定該條消息是否提交成功。

          三階段提交(3PC)

          三階段提交又稱3PC,相對于2PC來說增加了CanCommit階段和超時機制。如果段時間內(nèi)沒有收到協(xié)調(diào)者的commit請求,那么就會自動進行commit,解決了2PC單點故障的問題。

          但是性能問題和不一致問題仍然沒有根本解決。下面我們還是一起看下三階段流程的是什么樣的?

          • 第一階段:「CanCommit階段」這個階段所做的事很簡單,就是協(xié)調(diào)者詢問事務參與者,你是否有能力完成此次事務。

            • 如果都返回yes,則進入第二階段
            • 有一個返回no或等待響應超時,則中斷事務,并向所有參與者發(fā)送abort請求
          • 第二階段:「PreCommit階段」此時協(xié)調(diào)者會向所有的參與者發(fā)送PreCommit請求,參與者收到后開始執(zhí)行事務操作,并將Undo和Redo信息記錄到事務日志中。參與者執(zhí)行完事務操作后(此時屬于未提交事務的狀態(tài)),就會向協(xié)調(diào)者反饋“Ack”表示我已經(jīng)準備好提交了,并等待協(xié)調(diào)者的下一步指令。

          • 第三階段:「DoCommit階段」在階段二中如果所有的參與者節(jié)點都可以進行PreCommit提交,那么協(xié)調(diào)者就會從“預提交狀態(tài)”轉(zhuǎn)變?yōu)椤疤峤粻顟B(tài)”。然后向所有的參與者節(jié)點發(fā)送"doCommit"請求,參與者節(jié)點在收到提交請求后就會各自執(zhí)行事務提交操作,并向協(xié)調(diào)者節(jié)點反饋“Ack”消息,協(xié)調(diào)者收到所有參與者的Ack消息后完成事務。相反,如果有一個參與者節(jié)點未完成PreCommit的反饋或者反饋超時,那么協(xié)調(diào)者都會向所有的參與者節(jié)點發(fā)送abort請求,從而中斷事務。

          補償事務(TCC)

          TCC其實就是采用的補償機制,其核心思想是:「針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作」。它分為三個階段:

          「Try,Confirm,Cancel」

          • Try階段主要是對「業(yè)務系統(tǒng)做檢測及資源預留」,其主要分為兩個階段
            • Confirm 階段主要是對「業(yè)務系統(tǒng)做確認提交」,Try階段執(zhí)行成功并開始執(zhí)行 Confirm階段時,默認 Confirm階段是不會出錯的。即:只要Try成功,Confirm一定成功。
            • Cancel 階段主要是在業(yè)務執(zhí)行錯誤,需要回滾的狀態(tài)下執(zhí)行的業(yè)務取消,「預留資源釋放」。

          比如下一個訂單減一個庫存:

          執(zhí)行流程:

          • Try階段:訂單系統(tǒng)將當前訂單狀態(tài)設置為支付中,庫存系統(tǒng)校驗當前剩余庫存數(shù)量是否大于1,然后將可用庫存數(shù)量設置為庫存剩余數(shù)量-1,
            • 如果Try階段「執(zhí)行成功」,執(zhí)行Confirm階段,將訂單狀態(tài)修改為支付成功,庫存剩余數(shù)量修改為可用庫存數(shù)量
            • 如果Try階段「執(zhí)行失敗」,執(zhí)行Cancel階段,將訂單狀態(tài)修改為支付失敗,可用庫存數(shù)量修改為庫存剩余數(shù)量

          TCC 事務機制相比于上面介紹的2PC,解決了其幾個缺點:

          • 1.「解決了協(xié)調(diào)者單點」,由主業(yè)務方發(fā)起并完成這個業(yè)務活動。業(yè)務活動管理器也變成多點,引入集群。
          • 2.「同步阻塞」:引入超時,超時后進行補償,并且不會鎖定整個資源,將資源轉(zhuǎn)換為業(yè)務邏輯形式,粒度變小。
          • 3.「數(shù)據(jù)一致性」,有了補償機制之后,由業(yè)務活動管理器控制一致性

          總之,TCC 就是通過代碼人為實現(xiàn)了兩階段提交,不同的業(yè)務場景所寫的代碼都不一樣,并且很大程度的「增加」了業(yè)務代碼的「復雜度」,因此,這種模式并不能很好地被復用。

          本地消息表


          執(zhí)行流程:


          • 消息生產(chǎn)方,需要額外建一個消息表,并「記錄消息發(fā)送狀態(tài)」。消息表和業(yè)務數(shù)據(jù)要在一個事務里提交,也就是說他們要在一個數(shù)據(jù)庫里面。然后消息會經(jīng)過MQ發(fā)送到消息的消費方。

            • 如果消息發(fā)送失敗,會進行重試發(fā)送。
          • 消息消費方,需要「處理」這個「消息」,并完成自己的業(yè)務邏輯。

            • 如果是「業(yè)務上面的失敗」,可以給生產(chǎn)方「發(fā)送一個業(yè)務補償消息」,通知生產(chǎn)方進行回滾等操作。
            • 此時如果本地事務處理成功,表明已經(jīng)處理成功了
            • 如果處理失敗,那么就會重試執(zhí)行。
          • 生產(chǎn)方和消費方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發(fā)送一遍。

          消息事務

          消息事務的原理是將兩個事務「通過消息中間件進行異步解耦」,和上述的本地消息表有點類似,但是是通過消息中間件的機制去做的,其本質(zhì)就是'將本地消息表封裝到了消息中間件中'。

          執(zhí)行流程:

          • 發(fā)送prepare消息到消息中間件
          • 發(fā)送成功后,執(zhí)行本地事務
            • 如果事務執(zhí)行成功,則commit,消息中間件將消息下發(fā)至消費端
            • 如果事務執(zhí)行失敗,則回滾,消息中間件將這條prepare消息刪除
          • 消費端接收到消息進行消費,如果消費失敗,則不斷重試

          這種方案也是實現(xiàn)了「最終一致性」,對比本地消息表實現(xiàn)方案,不需要再建消息表,「不再依賴本地數(shù)據(jù)庫事務」了,所以這種方案更適用于高并發(fā)的場景。目前市面上實現(xiàn)該方案的「只有阿里的 RocketMQ」。

          最大努力通知

          最大努力通知的方案實現(xiàn)比較簡單,適用于一些最終一致性要求較低的業(yè)務。

          執(zhí)行流程:

          • 系統(tǒng) A 本地事務執(zhí)行完之后,發(fā)送個消息到 MQ;
          • 這里會有個專門消費 MQ 的服務,這個服務會消費 MQ 并調(diào)用系統(tǒng) B 的接口;
          • 要是系統(tǒng) B 執(zhí)行成功就 ok 了;要是系統(tǒng) B 執(zhí)行失敗了,那么最大努力通知服務就定時嘗試重新調(diào)用系統(tǒng) B, 反復 N 次,最后還是不行就放棄。

          Sagas 事務模型

          Saga事務模型又叫做長時間運行的事務

          其核心思想是「將長事務拆分為多個本地短事務」,由Saga事務協(xié)調(diào)器協(xié)調(diào),如果正常結(jié)束那就正常完成,如果「某個步驟失敗,則根據(jù)相反順序一次調(diào)用補償操作」。

          Seata框架中一個分布式事務包含3種角色:

          「Transaction Coordinator (TC)」:事務協(xié)調(diào)器,維護全局事務的運行狀態(tài),負責協(xié)調(diào)并驅(qū)動全局事務的提交或回滾。「Transaction Manager (TM)」:控制全局事務的邊界,負責開啟一個全局事務,并最終發(fā)起全局提交或全局回滾的決議。「Resource Manager (RM)」:控制分支事務,負責分支注冊、狀態(tài)匯報,并接收事務協(xié)調(diào)器的指令,驅(qū)動分支(本地)事務的提交和回滾。

          seata框架「為每一個RM維護了一張UNDO_LOG表」,其中保存了每一次本地事務的回滾數(shù)據(jù)。

          具體流程:1.首先TM 向 TC 申請「開啟一個全局事務」,全局事務「創(chuàng)建」成功并生成一個「全局唯一的 XID」。

          2.XID 在微服務調(diào)用鏈路的上下文中傳播。

          3.RM 開始執(zhí)行這個分支事務,RM首先解析這條SQL語句,「生成對應的UNDO_LOG記錄」。下面是一條UNDO_LOG中的記錄,UNDO_LOG表中記錄了分支ID,全局事務ID,以及事務執(zhí)行的redo和undo數(shù)據(jù)以供二階段恢復。

          4.RM在同一個本地事務中「執(zhí)行業(yè)務SQL和UNDO_LOG數(shù)據(jù)的插入」。在提交這個本地事務前,RM會向TC「申請關(guān)于這條記錄的全局鎖」。

          如果申請不到,則說明有其他事務也在對這條記錄進行操作,因此它會在一段時間內(nèi)重試,重試失敗則回滾本地事務,并向TC匯報本地事務執(zhí)行失敗。

          6.RM在事務提交前,「申請到了相關(guān)記錄的全局鎖」,然后直接提交本地事務,并向TC「匯報本地事務執(zhí)行成功」。此時全局鎖并沒有釋放,全局鎖的釋放取決于二階段是提交命令還是回滾命令。

          7.TC根據(jù)所有的分支事務執(zhí)行結(jié)果,向RM「下發(fā)提交或回滾」命令。

          • RM如果「收到TC的提交命令」,首先「立即釋放」相關(guān)記錄的全局「鎖」,然后把提交請求放入一個異步任務的隊列中,馬上返回提交成功的結(jié)果給 TC。異步隊列中的提交請求真正執(zhí)行時,只是刪除相應 UNDO LOG 記錄而已。

          • RM如果「收到TC的回滾命令」,則會開啟一個本地事務,通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄。將 UNDO LOG 中的后鏡與當前數(shù)據(jù)進行比較,

            • 如果不同,說明數(shù)據(jù)被當前全局事務之外的動作做了修改。這種情況,需要根據(jù)配置策略來做處理。
            • 如果相同,根據(jù) UNDO LOG 中的前鏡像和業(yè)務 SQL 的相關(guān)信息生成并執(zhí)行回滾的語句并執(zhí)行,然后提交本地事務達到回滾的目的,最后釋放相關(guān)記錄的全局鎖。

          總結(jié)

          本文介紹了分布式事務的一些基礎(chǔ)理論,并對常用的分布式事務方案進行了講解。

          分布式事務本身就是一個技術(shù)難題,業(yè)務中具體使用哪種方案還是需要不同的業(yè)務特點自行選擇,但是我們也會發(fā)現(xiàn),分布式事務會大大的提高流程的復雜度,會帶來很多額外的開銷工作,「代碼量上去了,業(yè)務復雜了,性能下跌了」

          所以,當我們真實開發(fā)的過程中,能不使用分布式事務就不使用。


          往期推薦

          一文掌握Redisson分布式鎖原理|干貨推薦


          阿里巴巴Druid,輕松實現(xiàn)MySQL數(shù)據(jù)庫加密!


          Google Guava,牛逼的腳手架


          瀏覽 65
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产在视频线精品视频www666 | AA级黄色一级黄色 | 亚洲婷婷网 | 操女生小逼| 夜夜干天天撸 |