https://zhuanlan.zhihu.com/p/437577902
分布式事務是系統(tǒng)拆分后需要解決的一大問題缨伊,市面上能搜到的相關資料和概念很多,比如 ACID、XA惫霸、2PC、3PC、TCC凰萨、SAGA、AT械馆、CAP胖眷、Base、最終一致性 ....... 霹崎,一只手完全數不過來珊搀,但是這些概念中間的聯(lián)系是什么卻很少有資料描述清楚,以致于學習的人好像懂了尾菇,好像又沒懂境析,沒辦法把這些知識串聯(lián)起來。
而這里我們會把分布式事務知識串聯(lián)起來成為體系派诬,理清楚這些概念中的邏輯劳淆。雖然知識點有點多篇幅會有點長,但正如文章標題默赂,這篇文章可以幫你通關分布式事務問題沛鸵。
一、單機事務的完美解決方案(ACID)
1.1缆八、什么是事務
所謂事務谒臼,就是說如何保證一組(多個)數據操作在執(zhí)行的過程中,要么全部執(zhí)行成功耀里,要么全部失敗,事務成功執(zhí)行后事務所變更的數據不會丟失拾氓,事務失敗后數據要回到事務開始之前的模樣冯挎。 簡潔點說就是一個事務里涉及到的 多個操作,要么全部執(zhí)行、要么全部不執(zhí)行房官。
1.2趾徽、事務的最終目的(數據的一致性)
在我們理解了事務的概念后,我們需要清楚另外一個更重要的問題翰守,那就是實現事務的最終目的是什么孵奶? 也就是說如果一組事務里的操作,有些執(zhí)行了蜡峰,有些沒有執(zhí)行了袁,此時會產生什么問題。 這時你可能會想到湿颅,要是你給你爸媽了1W塊錢载绿,結果你的賬戶錢扣了,但是你爸媽的賬戶里并沒有加上1W塊錢油航,也許你就該懷疑崭庸,你努力賺錢的意義是什么了。而這里你賬戶減少了1W塊錢谊囚,但是你爸媽賬戶沒有加上這1W怕享,這個就是“數據一致性問題”。
1.3镰踏、如何保證數據的一致性(AID)
A(原子性)函筋、C(一致性)、I(隔離性)余境、D(持久性)驻呐。C 是事務最終的目標,那么A芳来、I含末、D 就是為實現這個目標努力的打工仔,如果這幾個打工仔不能正常工作的話,那么一致性就得不到保障即舌。
原子性:這個很容易理解佣盒,因為它和事務的描述很像,保證一組操作要么全部執(zhí)行顽聂、要么全部不執(zhí)行肥惭,如果不保證原子性的話,那么就可能同一個事務里一個操作執(zhí)行了紊搪,而另外一個操作失敗蜜葱,所以會造成數據不一致的影響。
隔離性: 這個是說多個事務之間的操作不會相互影響耀石, 它們之間是相互隔離的牵囤。 如果不具備隔離性的話,那么兩個事務的操作就好像兩個人同時在一個畫布上畫畫,你畫的是豬揭鳞,他畫的是狗炕贵,結果兩個人在畫布上涂涂改改,最后畫出來的就是一個四不像了野崇。也就是說不保證隔離性称开,你修改數據的時候其它人也可以修改,那么也會造成數據不一致乓梨。
持久性:持久性是說鳖轰,事務一旦提交了,那么所產生的數據變更就不會因任何意外(數據庫故障督禽、服務器宕機)而導致數據丟失脆霎,因為一旦事務產生的部分數據丟了,那么還是會造成數據的不一致狈惫。
1.4睛蛛、AID的具體實現
原子性的實現
如何實現一組操作,要么全部執(zhí)行胧谈,要么全部都不執(zhí)行呢忆肾? 讓操作全部執(zhí)行看起來很簡單,因為這是程序正常的執(zhí)行完所有操作的結果菱肖。所以這里的關鍵是如何讓事務在不具備完成的條件時客冈,讓全部操作不執(zhí)行,也就是說當事務里某個操作不滿足執(zhí)行條件時稳强,就算有一部分操作執(zhí)行成功了场仲,那么我們依然可以通過某種方式可以把之前執(zhí)行成功的操作給撤銷。
為了解決上面的問題退疫,數據庫提供了一個用于記錄歷史數據的日志 undo log渠缕。 這個日志會在事務執(zhí)行前,首先對事務相關的原始數據進行記錄褒繁,當事務需要進行回滾撤銷之前已經完成的操作時亦鳞,通過undo log就可以把數據恢復到事務開始之前,這樣也就好像什么事情都沒發(fā)生過一樣棒坏。
隔離性的實現
隔離性的保障在各個領域都有一套通用的機制燕差,那就是鎖,多個事務需要操作同一個數據時坝冕,首先要獲得這個數據的鎖徒探,才能進行后續(xù)的操作,也只有前一個事務釋放了鎖之后喂窟,后面的事務才能拿到鎖刹帕, 所以通過鎖來隔離不同事務的操作吵血,從而保證事務的隔離性。
持久性的實現
持久性是說偷溺,只要事務提交了,那么事務所變更的數據就不會丟失(不管此時出現了什么故障)钱贯,在計算機里面能保證數據不丟失的唯一方式就是數據保存到磁盤了挫掏。 也就是說,持久性的難題是在于秩命,當程序或者硬件服務器出現故障時尉共,如何保證已經提交的事務所產生的數據能寫入到磁盤去(因為此時事務產生的數據還也許在內存,沒有寫到磁盤去)弃锐,所以事務提交之后袄友,如果發(fā)生故障,數據是很有可能丟失的霹菊。
為了解決這個問題剧蚣,所以就提供了一種數據重做日志(redo log),在事務提交之前旋廷,首先會把事務需要變更的數據提前以日志的形式記錄到磁盤中去(因為日志是以順序IO的形式寫入的鸠按,所以性能非常高),這樣在事務提交之后就算發(fā)生故障饶碘,事務所產生的數據丟失了目尖,那么也可以通過之前記錄的redo log 來對數據進行重做。
1.5扎运、ACID總結
在單機的事務實現里瑟曲,通過ACID得到了完美的解決。通過加鎖豪治,把需要操作相同數據的事務進行隔離洞拨,保證事務之間的操作相互不會產生影響,從而實現事務之間的隔離性鬼吵。在事務提交之前扣甲,首先記錄數據修改之前的日志(undo log) 和事務需要變更數據的日志(redo log),來保證事務不論在哪個階段都能通過undo log對事務數據進行回滾齿椅,把數據恢復到事務開始之前的模樣琉挖,然后通過redo log 來保證事務在提交之后,不論數據庫或服務器出現什么故障涣脚,都能把事務未成功寫入到磁盤的數據進行重做示辈。 最終通過undo log 和redo log 保證了事務的原子性和持久性。
二遣蚀、分布式事務能否完美解決(XA矾麻、2PC纱耻、3PC)
系統(tǒng)拆分為分布式之后,我們的事務概念邊界逐漸擴大了险耀, 由最開始只存在于一個進程的事務弄喘,而演變成多個進程惩激,甚至多個不同類型的進程事務逛艰。所以基于單進程的ACID實現機制已經無法滿足于新的事務形式了。雖然形式不同斥铺,但是前人的優(yōu)秀經驗還是可以借鑒的贬派,所以基于ACID的事務實現思路急但,由此衍生出了XA、2PC搞乏、3PC事務模型和協(xié)議波桩。
2.1、XA事務模型
單機事務的解決方案已經由ACID完美解決请敦,基本上也形成了一套不可動搖的規(guī)范镐躲,那么分布式事務的規(guī)范又由誰來定義呢,而XA就是立志于解決分布式事務并形成一套統(tǒng)一的規(guī)范冬三。
從單進程事務演變成多進程事務時匀油,場景發(fā)生了改變,之前是一個人做一件事勾笆,現在變成了多個人協(xié)作做一件事了敌蚜,一個人想對事務進行回滾還是提交 是很容易達成一致的,因為決定權在自己手上窝爪,不需要考慮其它人弛车。但是如何協(xié)調多個人一起進行統(tǒng)一的操作就是一個難題了,所以此時就必須要有一個統(tǒng)一的人來協(xié)調多個節(jié)點的操作蒲每,達到多個節(jié)點操作的一致性纷跛。
所以建立在每個節(jié)點都能保證自己節(jié)點的ACID特性前提上,XA的核心目標是解決如何協(xié)調多個節(jié)點之間的操作一致性邀杏。也就是如何在一個節(jié)點不滿足事務要求需要回滾的時候贫奠,可以讓大家一起回滾事務,如果大家都滿足事務完成條件時望蜡,可以讓大家一起提交事務唤崭。
XA 首先定義了兩種角色,全局的事務管理器(Transaction Manager) 和 局部資源管理器(resource Manager)脖律。這里全局事務管理器就是來協(xié)調各個節(jié)點統(tǒng)一操作的角色谢肾,通常我們也稱為事務協(xié)調者。局部資源管理器也就是參與事務執(zhí)行的進程小泉,通常我們也稱為事務參與者芦疏。 事務的執(zhí)行過程由協(xié)調者統(tǒng)一來決策冕杠,其它節(jié)點只需要按照協(xié)調者的指令來完成具體的事務操作即可。而協(xié)調者在協(xié)商各個事務節(jié)點的過程中酸茴、什么情況下決定集體提交事務分预,什么情況下又決定集體回滾事務,這里取決于XA事務模型里使用了哪種協(xié)商協(xié)議(2PC薪捍、3PC)噪舀。
2.2、2PC(兩階段提交協(xié)議)
2PC 協(xié)議的核心思路是協(xié)調者通過和參與者通過兩個階段的協(xié)商達到最終操作的一致性飘诗,首先第一階段的目的是確認各個參與者可否具備執(zhí)行事務的條件。然后根據第一階段各個參與者響應的結果界逛,制定出第二階段的事務策略昆稿。如果第一階段有任意一個參與者不具備事務執(zhí)行條件,那么第二階段的決策就是統(tǒng)一回滾息拜,只有在所有參與者都具備事務執(zhí)行的條件下溉潭,才進行整體事務的提交。
準備階段:
首先協(xié)調者向所有參與者發(fā)起Prepare指令少欺, 參與者收到指令后首先檢查是否具備事務執(zhí)行條件喳瓣,在具備條件后,參與者開始對事務相關的數據進行加鎖赞别、然后再生成事務相關日志(redo log畏陕、undo log),最后參與者會根據這兩個操作的執(zhí)行情況來向協(xié)調者響應成功或失敗仿滔。
提交階段
當協(xié)調者收到所有參與者的響應結果后惠毁,協(xié)調者會根據結果來做出最終決策,如果所有參與者都響應成功崎页,那么協(xié)調者會決定提交事務鞠绰,并且記錄全局事務信息(事務信息、狀態(tài)為commit)飒焦,然后向所有參與者發(fā)送commit指令蜈膨,參與者收到commit指令后會對上一階段生成的事務數據進行最后的提交。
當有任意一個參與者響應失斘(或者超時)翁巍,協(xié)調者會決定回滾事務,并且記錄全局事務狀態(tài)(事務信息志电、狀態(tài)為abort)曙咽,然后向所有參與者發(fā)送abort指令,當參與者收到abort指令后挑辆,會進行事務回滾例朱,清除上一個階段生成的redo log 和undo log孝情。
[圖片上傳失敗...(image-4b3b9c-1651584413630)]
2PC的異常場景處理機制
2PC在一切正常的情況下顯得很完美,一切都可以順利的進行洒嗤,不過總有一些意外是可觀存在的箫荡,比如說: 在協(xié)商的過程中 參與者掛掉怎么辦? 協(xié)調者掛掉怎么辦渔隶?羔挡? 消息在網絡傳輸的過程中丟失了怎么辦? 在遇到這些問題之后间唉,看2PC是如何進行應對的绞灼。
參與者掛掉
如果在第一階段,協(xié)調者發(fā)送Prepare指令給所有的參與者后呈野,參與者掛掉了低矮,那么此時協(xié)調者因為遲遲收不到參與者的消息而導致超時,所以協(xié)調者在超時之后會統(tǒng)一發(fā)送abort指令進行事務回滾被冒。
如果在第二階段军掂,協(xié)調者發(fā)送commit或者abort指令給所有參與者后,參與者掛掉了昨悼,那么協(xié)調者會在超時之后進行消息重發(fā)蝗锥,直到參與者恢復后收到到commit或者abort ,向協(xié)調者返回成功率触。
協(xié)調者掛掉
協(xié)調者在第一階段發(fā)送Prepare指令后掛掉终议,那么此時參與者此時會一直得不到協(xié)調者下一步的指令,那么此時參與者會一直陷入阻塞狀態(tài)闲延,資源也會一直被鎖住痊剖,直到協(xié)調者恢復之后向參與者發(fā)出下一步的指令。
協(xié)調者在第二階段掛掉垒玲,那么此時協(xié)調者已向所有者發(fā)出最后階段的指令了陆馁,所以收到指令的參與者會完成最后的commit或rollback操作,對于參與者來說事務已經結束合愈,所以不存在阻塞和鎖的問題叮贩, 當協(xié)調者恢復后,會把事務日志狀態(tài)標記為結束佛析。
因為網絡分區(qū)消息丟失
在第一階段益老,協(xié)調者發(fā)送給參與者的消息丟失了,那么此時參與者會因為沒有收到消息不會執(zhí)行任何動作寸莫,所以也不會響應協(xié)調者任何消息捺萌,此時協(xié)調者會因為沒有收到參與者的響應而超時,所以協(xié)調者會決定決定回滾事務膘茎,向所有參與者發(fā)送abort指令桃纯。
在第二階段酷誓,無論是協(xié)調者發(fā)送給參與者消息丟失、還是參與者響應協(xié)調者消息丟失态坦,都會導致協(xié)調者超時盐数,所以這種時候協(xié)調者會進行重試,直到所有參與者都響應成功伞梯。
極端情況下數據不一致的風險
我們發(fā)現在一般的的場景里玫氢,出現了問題2PC好像都能解決 ,但我們去抽絲剝繭的挖細節(jié)的時谜诫,就會發(fā)現2PC在某些場景會出現數據不一致的情況漾峡。
比如說,協(xié)調者在第二階段向部分參與者發(fā)送了commit指令后掛了喻旷,那么此時收到了commit指令的參與者會進行事務提交灰殴,然后未收到消息的參與者還是等著協(xié)調者的指令,所以這個時候會產生數據的不一致掰邢,此時必須要等協(xié)調者恢復之后重新發(fā)送指令,參與者才能達到最終的一致狀態(tài)伟阔。
還有如果在第二階段網絡發(fā)生問題導致部分消息丟失辣之,有些參與者收到了commit指令,有些參與者還沒有收到commit指令怀估,結果收到了指令的參與者提交了事務,沒收到消息的參與者還在等指令合搅,它不知道該進行回滾還是提交多搀,這個時候同樣也會產生數據不一致的問題。
2PC遺留問題
我們如果理解了2PC的實現機制后灾部,不難發(fā)現其中存在幾方面的問題康铭。
1、性能問題
從事務開始到事務最終提交或回滾赌髓,這期間所有參與者的資源一致處于鎖定狀態(tài)从藤,所以注定2PC的性能不會太高。
2锁蠕、數據不一致風險
從上面我們分析知道夷野,極端情況下不管是由于協(xié)調者故障,還是網絡分區(qū)都會有導致數據不一致的風險荣倾。
3悯搔、協(xié)調者故障導致的事務阻塞問題
在兩階段提交協(xié)議里,我們會發(fā)現協(xié)調者是一個至關重要角色舌仍,參與者無論任何時候出問題妒貌,都會在因為協(xié)調者沒收到參與者的消息而超時通危,協(xié)調者超時之后任然能做出下一步的決策,但是協(xié)調者問題后苏揣,流程就沒辦法繼續(xù)了黄鳍,此時參與者因為沒有收到協(xié)調者下一步指令不知道是該進行commit還是rollback(這里也許有人會有疑問,既然協(xié)調者可以超時平匈,那參與者為什么不可以超時呢框沟,這個問題放到3PC解答),所有的參與者必須等待協(xié)調者恢復之后才能做出下一步的動作增炭。
2PC總結:
1忍燥、2PC 核心是通過兩個階段的協(xié)商達到最終操作的一致性, 第一階段的目的是確認各個參與者可否具備執(zhí)行事務的條件隙姿。根據第一階段的結果然后第二階段再決定整體事務是進行提交還是回滾梅垄。
2、2PC大部分情況都能協(xié)商各個參與者達成一致输玷,但是在極端情況下(協(xié)調者掛了队丝、網絡分區(qū)),還是會產生數據不一致問題欲鹏,除此之外協(xié)調者單點故障會造成事務阻塞机久,然后2PC整個事務過程是會鎖定資源的,所有性能也不高赔嚎。
2.3膘盖、3PC(三階段提交協(xié)議)
通過3PC的名字我們也可能很自然的想到它是2PC的一個升級版,我們直覺也沒錯尤误,3PC就是想要解決2PC的遺留問題而誕生的侠畔。3PC包括詢問階段、準備階段损晤、提交階段,相對于2PC來說增加了一個詢問階段软棺,然后準備階段和2PC的準備階段大致類似,只是增加了參與者允許超時的機制尤勋,至于3PC的提交階段和2PC的提交階段邏輯一樣码党。 所以我們重點了解一下詢問階段,還有第二階段的參與者超時機制斥黑。
詢問階段
詢問階段的目的是核實所有參與者可否具備事務執(zhí)行條件揖盘。首先協(xié)調者開啟事務事務,然后向所有參與者發(fā)送CanCommit 指令詢問參與者是否具備事務執(zhí)行條件锌奴,參數者收到指令后兽狭,會根據檢測自己當前狀態(tài),判斷是否具備事務執(zhí)行條件,然后向協(xié)調者響應成功或失敗箕慧。
[圖片上傳失敗...(image-af27bc-1651584413630)]
如果協(xié)調者收到任何一個參與者失敗響應服球,那么此時會協(xié)調者會記錄全局事務信息(事務信息、狀態(tài)為abort)颠焦,然后向所有參與者發(fā)送abort指令斩熊。只有當所有參與者都響應成功之后,此時進入第二階段伐庭,協(xié)調者首先會記錄全局事務信息(事務信息粉渠、狀態(tài)為Precommit),然后向所有參與者發(fā)送precommit指令圾另。
準備階段
進入準備階段后霸株,協(xié)調者會所有參與者發(fā)送precommit指令。參與者收到指令后集乔,會開啟本地事務去件,鎖定事務對應的資源,然后記錄事務日志(Redo log Undo log)扰路,最后參與者根據本地事務的結果向協(xié)調者響應成功或失敗尤溜。
[圖片上傳失敗...(image-93b56c-1651584413630)]
當協(xié)調者收到任何一個參與者響應失敗,此時協(xié)調者會記錄全局事務信息(事務信息汗唱、狀態(tài)為abort)靴跛,然后向所有參與者發(fā)送abort指令。只有當所有參與者都響應成功之后渡嚣,此時進入第三階段,協(xié)調者首先會記錄全局事務信息(事務信息肥印、狀態(tài)為commit)识椰,然后向所有參與者發(fā)送docommit指令。
這里與2PC不同的是深碱,在進入準備階段后腹鹉,如果參與者遲遲沒有收到協(xié)調者的消息(網絡分區(qū)或協(xié)調者故障),那么此時參與者會有超時機制敷硅,當參與者超時之后會執(zhí)行統(tǒng)一默認策略進行事務commit功咒。
這里需要解釋一下為什么2PC里不允許參與者超時,而3PC里參與者就可以超時绞蹦。 這里核心的原因就是因為3PC增加了詢問階段力奋,一方面:因為能進入準備階段那么意味著所有參與者都通過了詢問階段,所有的參與者達成了一致幽七,并且具備執(zhí)行事務的條件了景殷,那么基本上可以確定參與者都可以成功執(zhí)行事務的。另外一方面 ,如果協(xié)調者掛了然后恢復后猿挚,協(xié)調者可以查看此時的全局事務狀態(tài)為Precommit咐旧,那此時協(xié)調者就知道自己掛掉之前是向參與者發(fā)送的什么指令,而且協(xié)調者也可以推斷出绩蜻,自己掛掉后參與者會因為超時統(tǒng)一執(zhí)行commit操作铣墨,這樣協(xié)調者就能根據當前的狀況作出下一步的決定。
但是2PC不一樣办绝,因為此時協(xié)調者和參與者才進行第一輪協(xié)商伊约,全局事務信息還沒有記錄任何狀態(tài),每個參與者都無法感知到其它參與者的事務情況八秃。如果參與者有超時機制碱妆,參與者在超時之后如果執(zhí)行Commit,那么如果有其它的參與者響應協(xié)調者的是失敗昔驱,那么全局事務最終的決策就是abort疹尾,那么此時參與者之間數據就不一致了。 如果參與者超時之后進行Rollback骤肛,那么假如參與者響應給協(xié)調者的消息是OK纳本,但是因為網絡延時,參與者超時了腋颠,但是最終協(xié)調者還是受到了參與者OK的指令繁成,此時全局事務會進入commit階段,那么也會造成數據的不一致淑玫。 另外一方面巾腕,協(xié)調者掛了恢復后,因為沒有判斷依據絮蒿,它也不知道各個參與者當前具體的情況尊搬,也沒辦法做出任何決策。
提交階段
如果在準備階段任意一個參與者響應失敗或者協(xié)調者超時土涝,協(xié)調者會決定進行事務回滾佛寿,首先記錄全局事務日志狀態(tài)為回滾,然后向所有參與者發(fā)送abort指令但壮,參與者收到abort指令會回滾本地事務冀泻,清除本地事務日志,然后響應協(xié)調者蜡饵。
[圖片上傳失敗...(image-20d0c1-1651584413630)]
如果所有參與者都響應成功弹渔,那么協(xié)調者會決定提交事務,首先會記錄全局事務信息狀態(tài)為commit溯祸,然后向所有參與者發(fā)送commit指令捞附,參與者收到commit指令后會對上一階段生成的事務信息進行最后的commit巾乳。
最后協(xié)調者收到所有參與者的成功響應后,將全局事務信息記錄為事務完成鸟召,否則任意一個協(xié)調者返回失敗或者超時胆绊,協(xié)調者都會一直進行重試,直到成功欧募。
3PC與2PC對比
1压状、性能問題(相比2PC性能更差)
2PC需要鎖定資源,并且時間取決于最慢的一個參與者跟继,在3PC里這樣的情況并未發(fā)生任何變化种冬,3PC也還是需要鎖定資源,同樣也是必須要等待所有參與者響應才能進行下一步流程舔糖,反而3PC增加了一個階段的協(xié)商通訊娱两,這就使得3PC通信成本更高,性能反而會更差金吗。
2十兢、協(xié)調者故障導致的事務阻塞問題(解決)
因為3PC增加了詢問階段,然后在準備階段增加了參與者超時機制摇庙,所以協(xié)調者故障并不會一直阻塞著事務進行旱物,參與者超時之后會進行事務commit。
3卫袒、數據不一致的風險(還是存在)
如果協(xié)調者第二階段的決策是abort宵呛,此時協(xié)調者把abort指令發(fā)送給了部分參與者之后掛掉了,那么收到了abort指令的參與者進行了數據回滾夕凝,但是沒有收到abort指令的參與者會根據超時機制進行事務commit宝穗,最終就會有部分參與者rollback了,部分參與者進行了commit码秉,最后數據不一致逮矛。
3PC總結:
1、3PC 增加了一個詢問階段泡徙、同時增加了超時機制,雖然階段了協(xié)調者故障導致阻塞的問題膜蠢,但是數據不一致的風險還是存在堪藐,而且性能因為多了一次網絡交互,反而變得更慢挑围。 正是因為這些原因 3PC也一直是處于一個理論的模型礁竞,而沒有實踐下去。
2.4杉辙、XA 強一致事務模型總結
1模捂、XA在單機事務ACID上的經驗,重新定義了分布式事務的強一致事務模型和規(guī)范。大家只要遵循這套規(guī)范狂男,各個應用之間就可以通過XA實現分布式事務综看。
2、XA定義了一種分布式事務模型岖食,抽象出了全局的事務管理器(協(xié)調者) 和 局部資源管理器(參與者)兩個角色红碑,協(xié)調者來統(tǒng)一協(xié)調各個參與者來達到操作的一致性,參與者根據協(xié)調者的指令來進行本地事務的處理泡垃。 協(xié)調者和參與者協(xié)商是通過用2PC的3PC協(xié)商協(xié)議達到操作的一致性析珊。
3、最終經過理論和實踐蔑穴,不管是用2PC還是3PC協(xié)議始終都存在數據不一致的風險忠寻,而且因為每個參與者的本地事務的鎖都需要等到整體事務結束才能真正的釋放,所以XA的性能問題也是一直被人詬病存和。
4奕剃、強一致事務模型是否還能完美的應用到分布式事務環(huán)境,到這里這條路線多少有些迷茫了哑姚,因為無論怎么優(yōu)化和增加協(xié)商的次數都還是會存在數據不一致的問題祭饭,而且強一致事務模型性能實在令人堪憂,直到CAP的出現才讓大家明白叙量,在分布式環(huán)境下完美的強一致是不可能實現的倡蝙,于是分布式事務的路線,逐漸開始放棄了追求完美強一致的路線绞佩,退而求其次的追求弱一致的解決方案寺鸥。
三、不可能完美(CAP)
強一致的事務一致性方案在單機事務能完美實現品山,但是在分布式事務場景并沒有到達預期的效果胆建,這其中本質的問題就在于單機事務和分布式事務所遇到的場景發(fā)生了變化,在單機事務里只需要單純的考慮數據一致性的問題肘交。但是分布式事務場景則需要兼顧數據一致性笆载、多節(jié)點的可用性、網絡分區(qū)多個問題, 所以強一致的事務模型始終無法完美的解決分布式事務場景涯呻。直到CAP理論出現逐漸成為了分布式計算領域公認的一個定理凉驻,此時大家才徹底放棄了繼續(xù)在強一致的模型上繼續(xù)耕耘。
3.1复罐、CAP 定義
CAP 理論主要描述了在一個分布式系統(tǒng)中涝登,它的一致性、可用性效诅、分區(qū)容錯性同時只能滿足兩個胀滚,必然會犧牲一個趟济。
一致性(C): 客戶端發(fā)出去的請求能讀取到最新的寫入結果。
可用性(A): 可用性就是客戶端發(fā)出的每個請求都能得到一個非錯誤的響應咽笼。
分區(qū)容錯性(P): 當出現消息丟失或者網絡分區(qū)錯誤時顷编,系統(tǒng)能夠繼續(xù)運行。
3.2褐荷、網絡分區(qū)發(fā)生的必然性( 只能在C與A中二選一)
因為網絡環(huán)境的不可靠勾效,分布式環(huán)境中節(jié)點也必需要通過網絡才能建立通訊,所以分布式環(huán)境中是無法避免網絡分區(qū)問題的叛甫,如果因為發(fā)生了網絡分區(qū)系統(tǒng)就無法使用层宫,那么分布式系統(tǒng)就沒有存在價值了,所以說在分布式環(huán)境中必須要滿足分區(qū)容錯性其监,那么系統(tǒng)在發(fā)生網絡分區(qū)的時候系統(tǒng)只能在一致性和可用性之間權衡萌腿。
3.3、以業(yè)務角度理解CAP
用戶向 用戶服務集群發(fā)起一筆扣款50的請求抖苦,此時請求被發(fā)送到用戶節(jié)點1處理毁菱,用戶節(jié)點1處理完之后把變更的數據再同步到用戶節(jié)點2中去,不過就在節(jié)點1同步到節(jié)點2的時候锌历,此時發(fā)生網絡分區(qū)税灌,節(jié)點1無法于節(jié)點2建立通訊柴钻,而正好此時用戶又向節(jié)點2發(fā)起了一個余額查詢請求隐轩。 那么此時我們會面臨下面兩種選擇:
[圖片上傳失敗...(image-6a8235-1651584413630)]
1图云、保證分區(qū)容忍性和可用性
如果在發(fā)生網絡分區(qū)時,為了保證系統(tǒng)的可用性卤材,此時節(jié)點2繼續(xù)向外正常提供服務遮斥。但是此時節(jié)點2中的數據與最新的數據是不一致的,所以在發(fā)生網絡分區(qū)的時候扇丛,此時為了保證系統(tǒng)的可用性术吗,就會犧牲掉數據的一致性。
2帆精、保證分區(qū)容忍性和一致性
如果在發(fā)生網絡分區(qū)時较屿,系統(tǒng)為了要避免對外提供不一致的業(yè)務數據,那么此時節(jié)點2會向用戶返回錯誤卓练,直到節(jié)點2同步到了最新的數據為止隘蝎,在此之前節(jié)點2都是不可用狀態(tài)。所以此時在發(fā)生網絡分區(qū)的時候昆庇,為了保證系統(tǒng)的數據的一致性末贾,就會犧牲掉系統(tǒng)的可用性闸溃。
所以根據推論證明整吆,在發(fā)生網絡分區(qū)的時候拱撵,分布式系統(tǒng)最多只能同時滿足兩個,如果選擇AP就會犧牲C表蝙,如果選擇CP就會犧牲A拴测,CAP無法同時滿足。
3.4府蛇、可用性和一致性如何選擇集索?
既然分布式系統(tǒng)里分區(qū)容錯必須容忍,那么也就意味著CAP里面只能在C或者A中進行選擇了汇跨。 那么C和A又該如何選擇呢务荆?
分析這個問題時,我們首先得回憶一下分布式系統(tǒng)的初衷穷遂, 不管是冗余節(jié)點函匕,還是拆分業(yè)務 ,這些措施的核心目的都是為了提高系統(tǒng)整體的可用性蚪黑,所以說如果選擇了CP盅惜,那么就會造成系統(tǒng)只要一發(fā)生網絡分區(qū)就導致部分功能不可用,結果因為系統(tǒng)分布式反而降低了我們系統(tǒng)可用性忌穿,那么這是否就違背了我們系統(tǒng)進行分布式的初衷抒寂? 所以從這一點來看,注定我們絕大部分的情況都是選擇 AP掠剑,而非CP屈芜。
總結:
1、CAP理論的出現結束了XA 強一致事務模型來解決分布式事務的繼續(xù)探索之路澡腾。
2沸伏、CAP通過理論證明了 在分布式系統(tǒng)里 可用性、分區(qū)容錯性动分、一致性無法同時滿足毅糟,最多同時只能滿足兩個。
3澜公、分布式系統(tǒng)里網絡分區(qū)無法避免姆另,所以只能在滿足P的情況下選擇CP或者AP。
4坟乾、分布式系統(tǒng)的初衷是提高系統(tǒng)整體的可用性迹辐,所以通常來說在CP和AP之間會選擇AP。
四甚侣、接受不完美(BASE)
CAP理論已經證明在分布式系統(tǒng)中CAP同時只能滿足CP或者AP明吩, 三個是無法同時滿足的,并且“分區(qū)容錯性”是分布式系統(tǒng)中必須要滿足的殷费,而“可用性”又是系統(tǒng)進行分布式設計的主要目的印荔,所以最終來看低葫,在分布式系統(tǒng)中我們的系統(tǒng)通常需要犧牲“一致性”來保證分區(qū)容錯性和可用性。
但是仍律,犧牲是否就意味著完全放棄一致性呢嘿悬? 并不是的,這里的犧牲是指“一段時間”水泉,在這段時間過后善涨,我們的系統(tǒng)最終還是要恢復到一致性的狀態(tài),通常我們也稱為最終一致性草则。Base理論就是基于最終一致性模型钢拧,提出的一套實踐理論,Base理論從基本可用炕横、軟狀態(tài)娶靡、最終一致性 三個層面指導我們進行分布式系統(tǒng)設計。
4.1看锉、基本可用(Basically Available)
系統(tǒng)發(fā)生故障時姿锭,允許犧牲一部分功能的可用性。 基本可用包括多個方面的指導含義伯铣,一方面是在系統(tǒng)故障時呻此,我們可以犧牲一些非核心功能的可用性來換取核心功能的可用性。另外一方面我們也可以犧牲一些用戶體驗, 比如 增加超時時間腔寡,只要系統(tǒng)恢復錯誤的時間快于請求超時時間焚鲜,那么對于客戶端來說整體系統(tǒng)還是可用的。
4.2放前、軟狀態(tài)(Soft State)
可以允許系統(tǒng)存在一些中間的狀態(tài)忿磅,因為網絡有延時,而這些延時可能會導致部分數據存在一定時差的不一致(比如說數據從一臺服務器同步到另外一臺服務器凭语,數據要經過網絡同步葱她,那么就必然會有一個時間差)。 所以說為了描述這些場景可能導致的數據不一致狀態(tài)似扔,我們系統(tǒng)可以設計一些軟狀態(tài)吨些、 比如說訂單有支付中、退款中炒辉、發(fā)貨中豪墅,因為有這些軟狀態(tài)的設計,所以我們的系統(tǒng)可以在數據不一致的情況繼續(xù)保持可用性黔寇。
4.3偶器、最終一致性(Eventually Consistent)
最終一致性是說,系統(tǒng)可以允許一段時間的不一致,但是經過一段時間后屏轰,最終數據要恢復一致术裸。
4.4、Base理論總結
Base理論是在CAP的理論基礎上做了進一步的延伸亭枷,CAP只告訴了我們什么可以,什么不可以搀崭,但是Base則是更具體的告訴我們具體應該從哪些方面去做叨粘,它的核心思想是,我們盡全力保證系統(tǒng)的可用性(AP)瘤睹,為實現這個目標升敲,在對應的場景中,我們設計一些軟狀態(tài)轰传、犧牲一些非核心功能的可用性來保障核心功能的正常驴党、允許一段時間的數據的不一致性,只能保證數據的最終一致性获茬。
五港庄、不完美的事務解決方案(最終一致性)
在CAP終結了在強一致事務上繼續(xù)探索的路后,基于Base理論 倡導的弱一致性的分布式事務實現方案逐漸興起恕曲,比如有基于消息鹏氧、TCC、SAGA 佩谣、AT等模式實現分布式事務最終一致性的解決方案把还。
(一)基于消息模式的實現方案
基于事件消息消息隊列實現一致性的模型中,事務發(fā)起方在完成本地事務后茸俭,會向調用方發(fā)送一個消息吊履,收到消息的事務參與者會執(zhí)行本地事務,多個事務合作的邏輯依次類推调鬓。 各個事務之間通過消息通知達實現分布式事務的操作艇炎,達到數據最終一致性。
1腾窝、消息模式實現過程
以用戶購買商品為例冕臭,用戶進行一次購買涉及到扣減余額(用戶服務)、扣減商品庫存(商品服務)燕锥,生成訂單信息(訂單服務)多個服務的事務處理辜贵。我們下面用消息隊列來解決用戶購買場景的分布式事務。
第一階段:
1归形、用戶服務 -執(zhí)行本地事務: 執(zhí)行本地事務托慨,扣減用戶余額。 生成事件表信息(事務ID暇榴,事務狀態(tài)(庫存扣減中))厚棵。
2蕉世、用戶服務 -向庫存服務發(fā)送消息:發(fā)送消息給商品服務進行庫存扣減。(如果不能保證消息發(fā)送的可靠性婆硬,那么此時就需要步驟3定時進行消息重發(fā)狠轻。)
3、用戶服務-定時任務:定時查詢事件表信息 中事務狀態(tài)彬犯,如果事務狀態(tài)為(庫存扣減中)向楼,那么向庫存服務發(fā)送消息。如果事務狀態(tài)為(訂單生成中)谐区,那么向訂單服務發(fā)送消息湖蜕。
第二階段:
1:商品服務-冪等性校驗:收到庫存扣消息消息,首先進行冪等性校驗宋列,該事務ID是否處理過昭抒,未處理則進行步驟2。已處理則進行步驟3.
2炼杖、商品服務-執(zhí)行本地事務:執(zhí)行本地事務灭返,扣減庫存,記錄已處理的事務ID(用于冪等性校驗)坤邪。
3婆殿、商品服務-向用戶服務發(fā)送消息:發(fā)送扣減庫存成功消息。
第三階段:
用戶服務-修改事件狀態(tài): 收到庫存扣減成功消息罩扇,修改事件表事務狀態(tài)為(訂單生成中)婆芦。
用戶服務-向訂單服務發(fā)送消息: 向訂單服務發(fā)送生成訂單消息。
第四階段:
1:訂單服務-冪等性校驗:收到庫生成訂單消息喂饥,首先進行冪等性校驗消约,該事務ID是否處理過,未處理則進行步驟2员帮。已處理則進行步驟3.
2或粮、訂單服務-執(zhí)行本地事務:執(zhí)行本地事務,生成訂單信息捞高,記錄已處理的事務ID(用于冪等性校驗)氯材。
3、訂單服務-向用戶服務發(fā)送消息:發(fā)送扣訂單創(chuàng)建成功消息硝岗。
第五階段:
用戶服務-事務完成: 收到訂單生成成功消息氢哮,修改事件表事務狀態(tài)為(事務完成)。
[圖片上傳失敗...(image-3b9603-1651584413630)]
2型檀、需要注意的地方
1冗尤、如何保證本地事務完成后,消息一定成功發(fā)送到下游服務。
因為本地事務和發(fā)送消息屬于兩個進程裂七,所以兩個操作無法保證同時成功皆看、同時失敗。 要解決這個問題通常使用本地事件消息表背零、和可靠消息隊列兩種方案腰吟。
本地事件消息表:因為消息可能發(fā)送失敗,那么我們就需要在本地記錄一個消息事件表徙瓶,保證然后保證業(yè)務和消息事件表在一個本地事務寫入到數據庫毛雇,這樣就能保證本地事務完成了,那么本地事件消息表就一定能成功寫入倍啥。然后通過一個額外的定時任務,定時查詢消息事務表里的事務狀態(tài)澎埠,如果事務狀態(tài)沒有變成預期的狀態(tài)虽缕,那么就會一直重試把消息發(fā)送給下一個業(yè)務流程的服務,直到事務完成蒲稳,這樣也就保證了消息一定會發(fā)送到下游服務氮趋。
可靠消息隊列:如果消息隊列支持事務消息(比如說RocketMQ),那么通過消息隊列的事務機制也可以保證本地事務和消息發(fā)送的事務江耀,在上面案例中可以省略掉定時任務的功能剩胁。
2、保證消息的冪等性
因為消息有重發(fā)機制祥国,所以接收消息的服務要具備業(yè)務操作的冪等性昵观。這里我們可以記錄一下業(yè)務唯一識別編號(比如全局事務ID),每次消費時核對一下對應事務ID的事務有沒有處理過舌稀,對于處理過的消息直接忽略啊犬。
3、消息模式總結
消息模式優(yōu)勢:
1壁查、性能高(相對于XA):基于消息隊列事務之間沒有任何阻塞觉至,都是純異步執(zhí),所以性能比較高睡腿。
2语御、實現簡單(相對于其它最終一致性方案):設計和實現上相對簡單,不需要過多的考慮失敗的情況席怪。应闯。
消息模式劣勢:
1、不適合業(yè)務需要回滾場景:基于消息每個事務都是異步執(zhí)行的挂捻,所以需通常我們要把最可能出錯的服務放到最前面孽锥,因為一旦向客戶端響應成功,但最終異步執(zhí)行后續(xù)事務的時候失敗,如果此時再進行回滾已經不太合適了(已經響應客戶端成功了),所以一旦事務檢查具備條件開始執(zhí)行惜辑,那么就會一直重試直到事務完成或者人工干預完成唬涧。
2、不具備資源隔離性: 兩個操作相同資源的事務可以同時進行盛撑,按上面的案例:商品總庫存為3碎节,兩個事務同時下單購買2個數量的商品,在驗證時都能通過抵卫,而扣減的時候已經沒辦法回滾業(yè)務了狮荔,結果最終就會出現商品超賣的情況。
3介粘、有業(yè)務侵入:需要基于實現方案殖氏,修改業(yè)務代碼。
消息模式適用場景:
本身業(yè)務比較簡單姻采,對事務實時性要求不高(異步和定時任務即時性不高)雅采,資源可進行一定程度調度(出現超支可以調度補充)、業(yè)務一般不會失敗或者就算失敗也不會對業(yè)務有很大影響慨亲, 比如說:通知婚瓜、數據同步類似場景。
(二)TCC模式
使用消息隊列的方式刑棵,一旦開始事務巴刻,那么意味著后續(xù)就必須要完成事務,沒有回滾的操作蛉签,也不具備隔離性胡陪,所以需要一種可以回滾業(yè)務、并且保證資源隔離性的事務模型碍舍。
而TCC為此提供了一個很好的解決方法督弓,首先TCC在事務執(zhí)行前,通過預留資源的方式把需要的資源事先隔離出來乒验,這樣就保證這部分的資源不被其它事務再次使用愚隧,然后為操作的失敗制定了一個補償操作來進行業(yè)務回滾,所以TCC的模式里是允許業(yè)務失敗的。
TCC分為Try锻全、Confirm狂塘、Cancel三個方法, Try階段主要是進行資源預留鳄厌,如果Try階段執(zhí)行成功荞胡,那么本次事務所需要的資源都已經獲得,這樣在事務提交的時候肯定能提交成功了嚎。如果Try階段失敗泪漂,那么此時就會調用Cancel操作進行資源釋放廊营。
Try階段: 該階段主要做業(yè)務可行性檢查并預留事務所需要的資源,保證預留出來的資源與其它的事務隔離開來萝勤。
Confirm:當所有事務參與者在Try階段都執(zhí)行成功后露筒,進入Confirm階段。此階段將直接使用Try階段預留資源進行業(yè)務操作敌卓。
cancel: 任意一個參與者在當Try階段執(zhí)行失敗慎式,則整體進入Cancel階段,此階段將釋放Try階段預留的資源趟径。
1瘪吏、TCC實現過程
以用戶購買商品為例,用于以金額100 下單購買了一件商品蜗巧,此時購買涉及到扣減余額(用戶服務)掌眠、扣減商品庫存(商品服務),生成訂單信息(訂單服務)多個服務的事務處理幕屹。我們下面TCC事務模型來解決用戶購買場景的分布式事務蓝丙。
Try階段:業(yè)務檢查,預留業(yè)務資源香嗓。
用戶服務:修改用戶凍結余額+100迅腔,修改用戶可用余額-100装畅。
商品服務:商品可用庫存-1靠娱,商品凍結庫存+1。
訂單服務:因為訂單創(chuàng)建不存在資源競爭掠兄,所以可以不用做資源預留操作像云,創(chuàng)建訂單也不會存在業(yè)務上的失敗,所以這個操作可以放到confirm里做蚂夕。
[圖片上傳失敗...(image-8c7ab7-1651584413630)]
Confirm階段:使用Try階段的預留資源迅诬。
用戶服務:用戶凍結余額-100。
商品服務:商品凍結庫存-1.
訂單服務:創(chuàng)建訂單信息婿牍。
[圖片上傳失敗...(image-fa77e-1651584413630)]
Cancel階段:釋放Try階段預留的資源侈贷。
用戶服務:用戶凍結余額-100,用戶可用余額+100等脂。
商品服務:商品可用庫存+1俏蛮,商品凍結庫存-1。
訂單服務:如果Try階段沒有創(chuàng)建訂單的話上遥,那么這里是一個空操作搏屑。
[圖片上傳失敗...(image-40e8fc-1651584413630)]
2、TCC模型中需要注意的問題
冪等問題(Confirm粉楚、Cancel被多次調用)
因為操作有重試機制辣恋,所以不管是Confirm操作還是Cancel操作亮垫,都需要具備操作冪等性,這里通常會通過保存一份本地事務日志伟骨,通過事務編號饮潦,來識別操作是否已經處理過。
空回滾問題(Try未執(zhí)行成功的情況執(zhí)行Cancel)
以上面的業(yè)務為例底靠,如果在Try階段 調用商品服務的Try方法害晦,此時商品服務的Try方法并未執(zhí)行成功。因為Try階段有服務失敗暑中,所以整體事務會進入Cancel階段壹瘟,因為Try階段并沒有預留資源成功,此時調用商品服務的Cancel業(yè)務就會導致問題鳄逾。
解決這個問題關鍵就是在Cancel階段需要知道Try階段有沒有執(zhí)行成功稻轨,如果執(zhí)行成功了才執(zhí)行釋放資源的邏輯,Try沒有執(zhí)行成功則不執(zhí)行具體的釋放資源邏輯雕凹。所以在Try階段的時候殴俱,如果執(zhí)行成功則需要向本地寫入一份事務日志,記錄當前Try操作成功枚抵。在Cancel階段則可以通過是否存在Try階段的事務日志來判斷是否需要執(zhí)行具體業(yè)務邏輯线欲。
資源懸掛問題 (Try比Cancel后執(zhí)行)
資源懸掛問題發(fā)生在一種比較極端的情況, 如果發(fā)送Try請求時發(fā)生網絡延時汽摹,那么請求方會認為業(yè)務失敗李丰,此時會進入Cancel階段,當所有的Cancel都執(zhí)行完之后逼泣,整個事務結束趴泌。但是之前發(fā)生網絡延時的請求最終還是發(fā)送到了對應的服務,此時會執(zhí)行Try操作拉庶,但是事務已經結束了嗜憔,沒有任何后續(xù)流程來提交或者釋放Try階段預留的資源。
解決這個問題氏仗,可以在Cancel階段也保留一條事務日志吉捶,Try執(zhí)行之前驗證Cancel階段的日志如果存在則不執(zhí)行具體業(yè)務。
3皆尔、TCC模式總結
TCC優(yōu)點:
1呐舔、性能高:沒有全局鎖,本地事務鎖在本地操作完成后馬上會釋放床佳,不會像2PC滋早、3PC 一樣整個事務執(zhí)行的過程都會鎖住資源,所以TCC性能非常高砌们。
2杆麸、具備隔離性: 通過隔離資源達到事務隔離的目的搁进,先預留資源,再真正使用資源昔头,避免了出現兩個事務并發(fā)時可能導致的同一個資源被使用多次的問題饼问,適合資源敏感的場景。
3揭斧、允許事務失斃掣铩:可以進行事務回滾。
TCC缺點:
1讹开、業(yè)務侵入性強: 需要修改原來的結構設計來預留資源盅视, 需要在原有的方法基礎上把業(yè)務拆分為Try、Confirm旦万、Cancel三個方法闹击。
TCC適用場景:
有資源隔離性要求、并且對業(yè)務系統(tǒng)有控制權成艘,有修改結構的權限赏半。
(三)SAGA模式
TCC需要修改原來的數據結構設計,實現這個需要對資源有可控權淆两,但是某些場景我們無法修改表結構設計(比如第三方系統(tǒng))断箫,那么TCC就的方法就不適用了。
SAGA的思想和TCC類似秋冰,TCC是先預留資源仲义,如果不行時再釋放,而SAGA的邏輯則是先直接使用資源丹莲,如果不行時再補償回去光坝。 這里的補償既可以通過回滾的方式實現補償尸诽,也可以單純的通過業(yè)務補償來實現(比如購買的商品庫存不足了甥材,商家可以退錢)。
SAGA通過補償的方式就不需要向TCC一樣對資源具備控制權性含,也不需要修改設計洲赵,只需要針對原來的每個接口,制定一個補償策略接口即可商蕴。 當事務執(zhí)行失敗時叠萍,逐個調用對應的補償接口,實現事務的回滾即可绪商。
1苛谷、SAGA的兩種模式
1、正向恢復: 正向恢復模式不提供補償機制格郁,如果某一個階段失敗了則采取重試機制腹殿,保證最終執(zhí)行成功独悴。
2、反向恢復:反向恢復則是提供補償機制锣尉,為每個接口都提供對應的補償接口刻炒,當某一個接口執(zhí)行失敗時(依次執(zhí)行A、B自沧、C接口坟奥,C接口執(zhí)行失敗)拇厢,則按逆序依次調用對應接口的補償接口(依次調用B爱谁、C 的補償接口)。
2孝偎、SAGA實現過程
以用戶下單購買商品為例,管行,此時購買涉及到扣減余額(用戶服務)、扣減商品庫存(商品服務)邪媳,生成訂單信息(訂單服務)多個服務的事務處理捐顷。我們下面SAGA事務模型來解決用戶購買場景的分布式事務。
正向恢復模式: 依次調用用戶服務扣減余額雨效、調用商品服務扣減庫存迅涮、調用訂單服務創(chuàng)建訂單,當某個服務返回失敗徽龟、則進行重試叮姑,直到成功或者人工干預。据悔。
[圖片上傳失敗...(image-7a6b58-1651584413630)]
反向恢復模式:
依次調用用戶服務扣減余額传透、調用商品服務扣減庫存、調用訂單服務創(chuàng)建訂單极颓,當某個服務返回失斨煅巍(比如這里訂單創(chuàng)建后失敗了),則依次逆序調用對應服務的補償接口進行業(yè)務補償菠隆,補償失敗則進行重試兵琳,直到成功或者人工干預。
[圖片上傳失敗...(image-168e4d-1651584413630)]
3骇径、使用SAGA注意點
和TCC一樣躯肌,SAGA也存在冪等、空回滾破衔、懸掛等問題清女,解決方案可參考TCC。
4、SAGA總結
SAGA 模式的優(yōu)點:
1庵芭、允許事務失斝艹铡:可以進行事務補償(相對于消息模式)哨苛。
2堕扶、對資源控制沒要求(相對于TCC)膘怕。
3外傅、比較簡單(相對于TCC)嗽仪,可以靈活的拆分事務粒度羊瘩,針對細粒度的接口制定對應的補償方案即可泰佳,容易理解和實現,適合用于長事務的解決方案尘吗。
SAGA模式的缺點:
1逝她、不具備隔離性,若涉及業(yè)務多睬捶,可能會出現某些業(yè)務在最終一致性前被再次操作黔宛,導致錯誤
2、有業(yè)務侵入性:需要對根據對應接口制定補償策略擒贸。
SAGA 模式的適用場景:
1臀晃、有第三方系統(tǒng)參與對資源沒有控制權,無法實現TCC模式的場景介劫。
2徽惋、遺留系統(tǒng)服務長事務場景。
3座韵、對隔離性沒要求而又需要補償機制的場景险绘。
(四)AT模式
不論是消息模式、TCC誉碴、還是SAGA 都對業(yè)務有一定程度的侵入性宦棺,就這一點來說對于開發(fā)人員來說是非常不友好的,那么有沒有一種模式能夠把這些回滾操作都自動化呢黔帕,這樣的話研發(fā)人員既不需要對業(yè)務進行改造代咸,又不用過渡關心分布式事務的處理機制,而 AT模式的出現則是廣大開發(fā)人員的福音蹬屹。
分布式開源框架Seata 中提出了一種AT模式分布式事務解決方案侣背,AT模式吸收了SAGA模式的思想白华,采用補償回滾事務的模式慨默,只不過這個補償不需要研發(fā)人員去編寫,AT模式中會針對每一個事務接口都自動生成對應的回滾SQL弧腥,當事務需要進行回滾時厦取,會自動執(zhí)行對應的回滾SQL,整個過程完全不需要開發(fā)人員參與和實現管搪。
AT模式整個實現過程是基于兩階段提交協(xié)議虾攻,協(xié)商過程中包含事務協(xié)調者(TC)铡买、事務發(fā)起者(TM)、資源所有者(RM)霎箍。協(xié)商過程和2PC類似奇钞,總體的邏輯就是RM在執(zhí)行SQL的時候首先會生成一個用于回滾的逆向SQL,然后所有RM會向TC匯報本地事務執(zhí)行狀態(tài)漂坏,當TC收到任何一個RM的事務失敗狀態(tài)景埃,那么TC會標記全局事務進行回滾,然后向所有RM發(fā)送回滾指令顶别,收到回滾指令的RM會根據自己本地的逆向SQL進行事務回滾谷徙。
1、Seata AT模式交互過程:
1驯绎、TM 向TC發(fā)起全局事務(這里的TM本身也是一個RM)完慧。
2、TC向TM返回全局事務ID剩失。
3屈尼、TM執(zhí)行本地事務,并生成逆向的SQL (保存到undo_log表里)和鎖數據(這的鎖數據是Seata生成的鎖拴孤,不是實際加在數據庫的鎖鸿染,只對通過Seata執(zhí)行的事務有效,這些鎖信息保存到了lock_table里)乞巧。
4涨椒、TM向TC注冊分支事務。
5绽媒、TC進行加鎖蚕冬,加鎖成功則會向TM返回成功,TM繼續(xù)往下執(zhí)行是辕。
6囤热、TM提交本地事務。
7获三、TM向TC上報分支事務狀態(tài)旁蔼。
8、TM調用下游服務RM疙教。
9棺聊、RM執(zhí)行本地事務,并生成逆向的SQL 和鎖數據贞谓。
10限佩、RM向TC注冊分支事務。
11、TC加鎖成功會向RM返回成功祟同,RM繼續(xù)往下執(zhí)行作喘。
12、RM提交本地事務晕城。
13泞坦、RM上報分支事務狀態(tài) (如果RM上報本地事務失敗,TC收到后砖顷,會決定整體事務進行回滾暇矫,然后向所有RM發(fā)送回滾指令,收到回滾指令的RM會執(zhí)行本地的逆向SQL回滾事務)择吊。
14李根、RM向TM返回成功。
15几睛、TM標記事務結束房轿。
[圖片上傳失敗...(image-3acdad-1651584413630)]
2、AT模式的總結
AT模式優(yōu)點
1所森、無業(yè)務侵入性: 集成Seta框架后囱持,使用只需一個注解即可。
2焕济、性能高: 不對數據庫加鎖纷妆,本地事務執(zhí)行完馬上釋放。
3晴弃、具備隔離性: 使用全局鎖則可保證事務隔離性掩幢,但全局鎖對性能有影響。
AT模式缺點
場景局限: 暫時來看AT模式其實是一個比較理想的分布式事務解決方案上鞠,就是現階段使用場景還有局限與數據庫層面的事務际邻。
補償模式的局限: 基于補償模式有些場景是不合適,特別是金融轉賬對資源非常敏感的芍阎,這種場景采用TCC模式更合適世曾。
六、終極大總結
1谴咸、在單機的事務實現里轮听,通過ACID得到了完美的解決。
2岭佳、分布式事務初期血巍,XA嘗試以ACID類似的模式完美的解決,但不管是2PC還是3PC 都無法避免一致性問題驼唱,而且用強一致事務模型的方式性能太差藻茂。
2、CPA告訴大家玫恳,分布式事務無法完美解決辨赐,C、A京办、P無法同時滿足掀序,并且P必須滿足、A又是大部分場景的選擇惭婿,所以通常只能選擇犧牲C不恭。
3、CAP告訴了我們什么可以财饥,什么不可以换吧,但Base 對CAP理論進一步進行了延伸,總結出了一套基于AP 事務的實踐方向钥星,我們可以通過犧牲一段時間的一致性沾瓦,設計一些軟狀態(tài),甚至舍棄一些非必要功能犧牲一些用戶體驗來保證系統(tǒng)的可用性谦炒。
4贯莺、既然強一致事務模型也沒辦法保證完美的數據一致性,何況強一致事務模型的性能那么令人堪憂宁改,那么我們又何必再執(zhí)著于最求強一致性呢缕探,所以基于Base理論的最終一致性事務方案逐漸發(fā)展起來,逐漸衍生出了基于消息模式还蹲、TCC爹耗、SAGA、AT幾種最終一致性事務模式谜喊。
5鲸沮、基于消息模式的實現方案簡單、但對代碼有侵入性锅论、不具備隔離性讼溺、也不適合需要回滾的事務。TCC具備隔離性最易、可回滾怒坯,但侵入性太強,代碼和數據都要自己能完全控制藻懒。 SAGA 可回滾剔猿、對資源控制沒要求,隔離性也可以通過加鎖解決嬉荆,但還是有侵入性归敬、而且基于補償模式在某些資源非常敏感的場景不適用。AT 模式使用簡單、具備隔離性汪茧、可回滾椅亚、無代碼侵入,唯一的問題就先階段AT模式只能解決數據庫層面的分布式事務舱污,還有基于補償模式的局限性呀舔,在某些資源非常敏感的場景不適用。
6扩灯、所以總結來看媚赖,首先最終一致性方案都要比強一致性方案的性能要高,另外強一致事務模型所支持數據庫/中間件也不多珠插,所以在這兩者上惧磺,我們一般都會選擇最終一致性事務模型。在最終一致性方案里捻撑,大部分場景使用AT模式即可磨隘,TCC可以作為補充方案解決資源敏感的場景,消息模式和SAGA可以作為AT和TCC模式無法實現的特定場景解決方案布讹。
各種方案綜合對比
[圖片上傳失敗...(image-a41001-1651584413629)]
參考書籍: