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

          七種分布式事務(wù)的解決方案,一次講給你聽

          共 5583字,需瀏覽 12分鐘

           ·

          2021-04-18 18:19

          本文約5300字,完整閱讀大概會(huì)花費(fèi)你「13分鐘」左右的時(shí)間
          [如果你覺得文章對你有幫助,歡迎關(guān)注,點(diǎn)贊,轉(zhuǎn)發(fā)]

          什么是分布式事務(wù)

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

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

          為什么會(huì)有分布式事務(wù)?

          舉個(gè)例子:

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

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

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

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

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

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

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

          分布式理論

          CAP定理

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

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

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

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

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

          BASE理論

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

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

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

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

          分布式事務(wù)解決方案

          兩階段提交(2PC)

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

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

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

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

          事務(wù)的提交分成兩個(gè)階段

          第一個(gè)階段是「投票階段」

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

          第二個(gè)階段是「決定階段」

          當(dāng)A節(jié)點(diǎn)收到B和C參與者所有的確認(rèn)消息后

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

          可能會(huì)存在哪些問題?

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

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

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

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

          三階段提交(3PC)

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

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

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

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

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

          補(bǔ)償事務(wù)(TCC)

          TCC其實(shí)就是采用的補(bǔ)償機(jī)制,其核心思想是:「針對每個(gè)操作,都要注冊一個(gè)與其對應(yīng)的確認(rèn)和補(bǔ)償(撤銷)操作」。它分為三個(gè)階段:

          「Try,Confirm,Cancel」

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

          比如下一個(gè)訂單減一個(gè)庫存:

          執(zhí)行流程:

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

          TCC 事務(wù)機(jī)制相比于上面介紹的2PC,解決了其幾個(gè)缺點(diǎn):

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

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

          本地消息表


          執(zhí)行流程:


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

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

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

          消息事務(wù)

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

          執(zhí)行流程:

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

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

          最大努力通知

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

          執(zhí)行流程:

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

          Sagas 事務(wù)模型

          Saga事務(wù)模型又叫做長時(shí)間運(yùn)行的事務(wù)

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

          Seata框架中一個(gè)分布式事務(wù)包含3種角色:

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

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

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

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

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

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

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

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

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

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

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

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

          總結(jié)

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

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

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

          -END-


          如果你能看到這里,那么下面這套教程,你一定要領(lǐng)??!最近有讀者想要分布式的項(xiàng)目,還有想要商城的,還有想要springboot,springcloud,k8s等等,這次直接分享幾乎涵蓋了我們java程序員的大部分技術(shù)桟,可以說真的非常全面了。強(qiáng)烈建議大家都上手做一做,而且以后肯定用的上。資料包含高清視頻+課件+源碼……

          掃以下二維碼并回復(fù)“99”即可獲取


          瀏覽 26
          點(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>
                  日本三级网| 无码一区二区三区四区五 | 成人伊人网在线观看 | 欧美日韩在线一区 | 女人18片毛片90分钟视频播放 |