怎么解析分布式事務(wù),相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,提供成都做網(wǎng)站、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);可快速的進(jìn)行網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,是專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
前言
事務(wù)想必大家并不陌生,至于什么是 ACID,也是老生常談了。不過暖男為了保證文章的完整性確保所有人都聽得懂,我還是得先說說 ACID,然后再來介紹下什么是分布式事務(wù)和常見的分布式事務(wù)包括 2PC、3PC、TCC、本地消息表、消息事務(wù)、最大努力通知。
事務(wù)
嚴(yán)格意義上的事務(wù)實現(xiàn)應(yīng)該是具備原子性、一致性、隔離性和持久性,簡稱 ACID。
原子性(Atomicity),可以理解為一個事務(wù)內(nèi)的所有操作要么都執(zhí)行,要么都不執(zhí)行。
一致性(Consistency),可以理解為數(shù)據(jù)是滿足完整性約束的,也就是不會存在中間狀態(tài)的數(shù)據(jù),比如你賬上有400,我賬上有100,你給我打200塊,此時你賬上的錢應(yīng)該是200,我賬上的錢應(yīng)該是300,不會存在我賬上錢加了,你賬上錢沒扣的中間狀態(tài)。
隔離性(Isolation),指的是多個事務(wù)并發(fā)執(zhí)行的時候不會互相干擾,即一個事務(wù)內(nèi)部的數(shù)據(jù)對于其他事務(wù)來說是隔離的。
持久性(Durability),指的是一個事務(wù)完成了之后數(shù)據(jù)就被永遠(yuǎn)保存下來,之后的其他操作或故障都不會對事務(wù)的結(jié)果產(chǎn)生影響。
而通俗意義上事務(wù)就是為了使得一些更新操作要么都成功,要么都失敗。
說到這里可能有人會說,不對啊 redis 的事務(wù)不能保證所有操作要么都執(zhí)行要么都不執(zhí)行,為什么它也叫事務(wù)啊?
首先你要知曉一般的中間件都會夸大其效果,人家團(tuán)隊也是想更出名,吸引更多的人來使用他們的產(chǎn)品,所以我們得以辯證的角度來看待。
一般而言他們既然敢說出他們實現(xiàn)了什么什么,要么是真的實現(xiàn)了,要么是在某種特殊、定制或者極端的條件下才能滿足功能。
我們來看看 Redis 怎么說的。
這句話就是告訴大家事務(wù)中的某個命令失敗了,之后的命令還是會被處理,Redis 不會停止命令,意味著也不會回滾。
你說這不是扯嘛?這都偏離事務(wù)最核心的本意了啊。
別急,咱們來看看 Redis 怎么解釋的。
Redis 官網(wǎng)解釋了為什么不支持回滾,他們說首先如果命令出錯那都是語法使用錯誤,是你們自己編程出錯,而且這種情況應(yīng)該在開發(fā)的時候就被檢測出來,不應(yīng)在生產(chǎn)環(huán)境中出現(xiàn)。
然后 Redis 就是為了快!不需要提供回滾。
下面還有一段話我就不截圖了,就是說就算提供回滾也沒用,你這代碼都寫錯了,回滾并不能使你免于編程錯誤。而且一般這種錯也不可能進(jìn)入到生產(chǎn)環(huán)境,所以選擇更加簡單、快速的方法,我們不支持回滾。
你看看這說的好像很有道理,我們不提供回滾,因為我們不需要為你的編程錯誤買單!
但好像哪里不對勁?角度、立場不同,大家自己品。
就下來就開始分布式事務(wù)。
分布式事務(wù)
分布式事務(wù)顧名思義就是要在分布式系統(tǒng)中實現(xiàn)事務(wù),它其實是由多個本地事務(wù)組合而成。
對于分布式事務(wù)而言幾乎滿足不了 ACID,其實對于單機(jī)事務(wù)而言大部分情況下也沒有滿足 ACID,不然怎么會有四種隔離級別呢?所以更別說分布在不同數(shù)據(jù)庫或者不同應(yīng)用上的分布式事務(wù)了。
我們先來看下 2PC。
2PC
2PC(Two-phase commit protocol),中文叫二階段提交。二階段提交是一種強(qiáng)一致性設(shè)計,2PC 引入一個事務(wù)協(xié)調(diào)者的角色來協(xié)調(diào)管理各參與者(也可稱之為各本地資源)的提交和回滾,二階段分別指的是準(zhǔn)備(投票)和提交兩個階段。
注意這只是協(xié)議或者說是理論指導(dǎo),只闡述了大方向,具體落地還是有會有差異的。
讓我們來看下兩個階段的具體流程。
準(zhǔn)備階段協(xié)調(diào)者會給各參與者發(fā)送準(zhǔn)備命令,你可以把準(zhǔn)備命令理解成除了提交事務(wù)之外啥事都做完了。
同步等待所有資源的響應(yīng)之后就進(jìn)入第二階段即提交階段(注意提交階段不一定是提交事務(wù),也可能是回滾事務(wù))。
假如在第一階段所有參與者都返回準(zhǔn)備成功,那么協(xié)調(diào)者則向所有參與者發(fā)送提交事務(wù)命令,然后等待所有事務(wù)都提交成功之后,返回事務(wù)執(zhí)行成功。
讓我們來看一下流程圖。
假如在第一階段有一個參與者返回失敗,那么協(xié)調(diào)者就會向所有參與者發(fā)送回滾事務(wù)的請求,即分布式事務(wù)執(zhí)行失敗。
那可能就有人問了,那第二階段提交失敗的話呢?
這里有兩種情況。
第一種是第二階段執(zhí)行的是回滾事務(wù)操作,那么答案是不斷重試,直到所有參與者都回滾了,不然那些在第一階段準(zhǔn)備成功的參與者會一直阻塞著。
第二種是第二階段執(zhí)行的是提交事務(wù)操作,那么答案也是不斷重試,因為有可能一些參與者的事務(wù)已經(jīng)提交成功了,這個時候只有一條路,就是頭鐵往前沖,不斷的重試,直到提交成功,到最后真的不行只能人工介入處理。
大體上二階段提交的流程就是這樣,我們再來看看細(xì)節(jié)。
首先 2PC 是一個同步阻塞協(xié)議,像第一階段協(xié)調(diào)者會等待所有參與者響應(yīng)才會進(jìn)行下一步操作,當(dāng)然第一階段的協(xié)調(diào)者有超時機(jī)制,假設(shè)因為網(wǎng)絡(luò)原因沒有收到某參與者的響應(yīng)或某參與者掛了,那么超時后就會判斷事務(wù)失敗,向所有參與者發(fā)送回滾命令。
在第二階段協(xié)調(diào)者的沒法超時,因為按照我們上面分析只能不斷重試!
協(xié)調(diào)者故障分析
協(xié)調(diào)者是一個單點,存在單點故障問題。
假設(shè)協(xié)調(diào)者在發(fā)送準(zhǔn)備命令之前掛了,還行等于事務(wù)還沒開始。
假設(shè)協(xié)調(diào)者在發(fā)送準(zhǔn)備命令之后掛了,這就不太行了,有些參與者等于都執(zhí)行了處于事務(wù)資源鎖定的狀態(tài)。不僅事務(wù)執(zhí)行不下去,還會因為鎖定了一些公共資源而阻塞系統(tǒng)其它操作。
假設(shè)協(xié)調(diào)者在發(fā)送回滾事務(wù)命令之前掛了,那么事務(wù)也是執(zhí)行不下去,且在第一階段那些準(zhǔn)備成功參與者都阻塞著。
假設(shè)協(xié)調(diào)者在發(fā)送回滾事務(wù)命令之后掛了,這個還行,至少命令發(fā)出去了,很大的概率都會回滾成功,資源都會釋放。但是如果出現(xiàn)網(wǎng)絡(luò)分區(qū)問題,某些參與者將因為收不到命令而阻塞著。
假設(shè)協(xié)調(diào)者在發(fā)送提交事務(wù)命令之前掛了,這個不行,傻了!這下是所有資源都阻塞著。
假設(shè)協(xié)調(diào)者在發(fā)送提交事務(wù)命令之后掛了,這個還行,也是至少命令發(fā)出去了,很大概率都會提交成功,然后釋放資源,但是如果出現(xiàn)網(wǎng)絡(luò)分區(qū)問題某些參與者將因為收不到命令而阻塞著。
協(xié)調(diào)者故障,通過選舉得到新協(xié)調(diào)者
因為協(xié)調(diào)者單點問題,因此我們可以通過選舉等操作選出一個新協(xié)調(diào)者來頂替。
如果處于第一階段,其實影響不大都回滾好了,在第一階段事務(wù)肯定還沒提交。
如果處于第二階段,假設(shè)參與者都沒掛,此時新協(xié)調(diào)者可以向所有參與者確認(rèn)它們自身情況來推斷下一步的操作。
假設(shè)有個別參與者掛了!這就有點僵硬了,比如協(xié)調(diào)者發(fā)送了回滾命令,此時第一個參與者收到了并執(zhí)行,然后協(xié)調(diào)者和第一個參與者都掛了。
此時其他參與者都沒收到請求,然后新協(xié)調(diào)者來了,它詢問其他參與者都說OK,但它不知道掛了的那個參與者到底O不OK,所以它傻了。
問題其實就出在每個參與者自身的狀態(tài)只有自己和協(xié)調(diào)者知道,因此新協(xié)調(diào)者無法通過在場的參與者的狀態(tài)推斷出掛了的參與者是什么情況。
雖然協(xié)議上沒說,不過在實現(xiàn)的時候我們可以靈活的讓協(xié)調(diào)者將自己發(fā)過的請求在哪個地方記一下,也就是日志記錄,這樣新協(xié)調(diào)者來的時候不就知道此時該不該發(fā)了?
但是就算協(xié)調(diào)者知道自己該發(fā)提交請求,那么在參與者也一起掛了的情況下沒用,因為你不知道參與者在掛之前有沒有提交事務(wù)。
如果參與者在掛之前事務(wù)提交成功,新協(xié)調(diào)者確定存活著的參與者都沒問題,那肯定得向其他參與者發(fā)送提交事務(wù)命令才能保證數(shù)據(jù)一致。
如果參與者在掛之前事務(wù)還未提交成功,參與者恢復(fù)了之后數(shù)據(jù)是回滾的,此時協(xié)調(diào)者必須是向其他參與者發(fā)送回滾事務(wù)命令才能保持事務(wù)的一致。
所以說極端情況下還是無法避免數(shù)據(jù)不一致問題。
talk is cheap 讓我們再來看下代碼,可能更加的清晰。以下代碼取自 <>。
這個代碼就是實現(xiàn)了 2PC,但是相比于2PC增加了寫日志的動作、參與者之間還會互相通知、參與者也實現(xiàn)了超時。這里要注意,一般所說的2PC,不含上述功能,這都是實現(xiàn)的時候添加的。
協(xié)調(diào)者: write START_2PC to local log; //開始事務(wù) multicast VOTE_REQUEST to all participants; //廣播通知參與者投票 while not all votes have been collected { wait for any incoming vote; if timeout { //協(xié)調(diào)者超時 write GLOBAL_ABORT to local log; //寫日志 multicast GLOBAL_ABORT to all participants; //通知事務(wù)中斷 exit; } record vote; } //如果所有參與者都o(jì)k if all participants sent VOTE_COMMIT and coordinator votes COMMIT { write GLOBAL_COMMIT to local log; multicast GLOBAL_COMMIT to all participants; } else { write GLOBAL_ABORT to local log; multicast GLOBAL_ABORT to all participants; } 參與者: write INIT to local log; //寫日志 wait for VOTE_REQUEST from coordinator; if timeout { //等待超時 write VOTE_ABORT to local log; exit; } if participant votes COMMIT { write VOTE_COMMIT to local log; //記錄自己的決策 send VOTE_COMMIT to coordinator; wait for DECISION from coordinator; if timeout { multicast DECISION_REQUEST to other participants; //超時通知 wait until DECISION is received; /* remain blocked*/ write DECISION to local log; } if DECISION == GLOBAL_COMMIT write GLOBAL_COMMIT to local log; else if DECISION == GLOBAL_ABORT write GLOBAL_ABORT to local log; } else { write VOTE_ABORT to local log; send VOTE_ABORT to coordinator; } 每個參與者維護(hù)一個線程處理其它參與者的DECISION_REQUEST請求: while true { wait until any incoming DECISION_REQUEST is received; read most recently recorded STATE from the local log; if STATE == GLOBAL_COMMIT send GLOBAL_COMMIT to requesting participant; else if STATE == INIT or STATE == GLOBAL_ABORT; send GLOBAL_ABORT to requesting participant; else skip; /* participant remains blocked */ }
至此我們已經(jīng)詳細(xì)的分析的 2PC 的各種細(xì)節(jié),我們來總結(jié)一下!
2PC 是一種盡量保證強(qiáng)一致性的分布式事務(wù),因此它是同步阻塞的,而同步阻塞就導(dǎo)致長久的資源鎖定問題,總體而言效率低,并且存在單點故障問題,在極端條件下存在數(shù)據(jù)不一致的風(fēng)險。
當(dāng)然具體的實現(xiàn)可以變形,而且 2PC 也有變種,例如 Tree 2PC、Dynamic 2PC。
還有一點不知道你們看出來沒,2PC 適用于數(shù)據(jù)庫層面的分布式事務(wù)場景,而我們業(yè)務(wù)需求有時候不僅僅關(guān)乎數(shù)據(jù)庫,也有可能是上傳一張圖片或者發(fā)送一條短信。
而且像 Java 中的 JTA 只能解決一個應(yīng)用下多數(shù)據(jù)庫的分布式事務(wù)問題,跨服務(wù)了就不能用了。
簡單說下 Java 中 JTA,它是基于XA規(guī)范實現(xiàn)的事務(wù)接口,這里的 XA 你可以簡單理解為基于數(shù)據(jù)庫的 XA 規(guī)范來實現(xiàn)的 2PC。(至于XA規(guī)范到底是啥,篇幅有限,下次有機(jī)會再說)
接下來我們再來看看 3PC。
3PC
3PC 的出現(xiàn)是為了解決 2PC 的一些問題,相比于 2PC 它在參與者中也引入了超時機(jī)制,并且新增了一個階段使得參與者可以利用這一個階段統(tǒng)一各自的狀態(tài)。
讓我們來詳細(xì)看一下。
3PC 包含了三個階段,分別是準(zhǔn)備階段、預(yù)提交階段和提交階段,對應(yīng)的英文就是:CanCommit、PreCommit 和 DoCommit。
看起來是把 2PC 的提交階段變成了預(yù)提交階段和提交階段,但是 3PC 的準(zhǔn)備階段協(xié)調(diào)者只是詢問參與者的自身狀況,比如你現(xiàn)在還好嗎?負(fù)載重不重?這類的。
而預(yù)提交階段就是和 2PC 的準(zhǔn)備階段一樣,除了事務(wù)的提交該做的都做了。
提交階段和 2PC 的一樣,讓我們來看一下圖。
不管哪一個階段有參與者返回失敗都會宣布事務(wù)失敗,這和 2PC 是一樣的(當(dāng)然到最后的提交階段和 2PC 一樣只要是提交請求就只能不斷重試)。
我們先來看一下 3PC 的階段變更有什么影響。
首先準(zhǔn)備階段的變更成不會直接執(zhí)行事務(wù),而是會先去詢問此時的參與者是否有條件接這個事務(wù),因此不會一來就干活直接鎖資源,使得在某些資源不可用的情況下所有參與者都阻塞著。
而預(yù)提交階段的引入起到了一個統(tǒng)一狀態(tài)的作用,它像一道柵欄,表明在預(yù)提交階段前所有參與者其實還未都回應(yīng),在預(yù)處理階段表明所有參與者都已經(jīng)回應(yīng)了。
假如你是一位參與者,你知道自己進(jìn)入了預(yù)提交狀態(tài)那你就可以推斷出來其他參與者也都進(jìn)入了預(yù)提交狀態(tài)。
但是多引入一個階段也多一個交互,因此性能會差一些,而且絕大部分的情況下資源應(yīng)該都是可用的,這樣等于每次明知可用執(zhí)行還得詢問一次。
我們再來看下參與者超時能帶來什么樣的影響。
我們知道 2PC 是同步阻塞的,上面我們已經(jīng)分析了協(xié)調(diào)者掛在了提交請求還未發(fā)出去的時候是最傷的,所有參與者都已經(jīng)鎖定資源并且阻塞等待著。
那么引入了超時機(jī)制,參與者就不會傻等了,如果是等待提交命令超時,那么參與者就會提交事務(wù)了,因為都到了這一階段了大概率是提交的,如果是等待預(yù)提交命令超時,那該干啥就干啥了,反正本來啥也沒干。
然而超時機(jī)制也會帶來數(shù)據(jù)不一致的問題,比如在等待提交命令時候超時了,參與者默認(rèn)執(zhí)行的是提交事務(wù)操作,但是有可能執(zhí)行的是回滾操作,這樣一來數(shù)據(jù)就不一致了。
當(dāng)然 3PC 協(xié)調(diào)者超時還是在的,具體不分析了和 2PC 是一樣的。
從維基百科上看,3PC 的引入是為了解決提交階段 2PC 協(xié)調(diào)者和某參與者都掛了之后新選舉的協(xié)調(diào)者不知道當(dāng)前應(yīng)該提交還是回滾的問題。
新協(xié)調(diào)者來的時候發(fā)現(xiàn)有一個參與者處于預(yù)提交或者提交階段,那么表明已經(jīng)經(jīng)過了所有參與者的確認(rèn)了,所以此時執(zhí)行的就是提交命令。
所以說 3PC 就是通過引入預(yù)提交階段來使得參與者之間的狀態(tài)得到統(tǒng)一,也就是留了一個階段讓大家同步一下。
但是這也只能讓協(xié)調(diào)者知道該如果做,但不能保證這樣做一定對,這其實和上面 2PC 分析一致,因為掛了的參與者到底有沒有執(zhí)行事務(wù)無法斷定。
所以說 3PC 通過預(yù)提交階段可以減少故障恢復(fù)時候的復(fù)雜性,但是不能保證數(shù)據(jù)一致,除非掛了的那個參與者恢復(fù)。
讓我們總結(jié)一下, 3PC 相對于 2PC 做了一定的改進(jìn):引入了參與者超時機(jī)制,并且增加了預(yù)提交階段使得故障恢復(fù)之后協(xié)調(diào)者的決策復(fù)雜度降低,但整體的交互過程更長了,性能有所下降,并且還是會存在數(shù)據(jù)不一致問題。
所以 2PC 和 3PC 都不能保證數(shù)據(jù)100%一致,因此一般都需要有定時掃描補償機(jī)制。
我再說下 3PC 我沒有找到具體的實現(xiàn),所以我認(rèn)為 3PC 只是純的理論上的東西,而且可以看到相比于 2PC 它是做了一些努力但是效果甚微,所以只做了解即可。
TCC
2PC 和 3PC 都是數(shù)據(jù)庫層面的,而 TCC 是業(yè)務(wù)層面的分布式事務(wù),就像我前面說的分布式事務(wù)不僅僅包括數(shù)據(jù)庫的操作,還包括發(fā)送短信等,這時候 TCC 就派上用場了!
TCC 指的是Try - Confirm - Cancel。
Try 指的是預(yù)留,即資源的預(yù)留和鎖定,注意是預(yù)留。
Confirm 指的是確認(rèn)操作,這一步其實就是真正的執(zhí)行了。
Cancel 指的是撤銷操作,可以理解為把預(yù)留階段的動作撤銷了。
其實從思想上看和 2PC 差不多,都是先試探性的執(zhí)行,如果都可以那就真正的執(zhí)行,如果不行就回滾。
比如說一個事務(wù)要執(zhí)行A、B、C三個操作,那么先對三個操作執(zhí)行預(yù)留動作。如果都預(yù)留成功了那么就執(zhí)行確認(rèn)操作,如果有一個預(yù)留失敗那就都執(zhí)行撤銷動作。
我們來看下流程,TCC模型還有個事務(wù)管理者的角色,用來記錄TCC全局事務(wù)狀態(tài)并提交或者回滾事務(wù)。
可以看到流程還是很簡單的,難點在于業(yè)務(wù)上的定義,對于每一個操作你都需要定義三個動作分別對應(yīng)Try - Confirm - Cancel。
因此 TCC 對業(yè)務(wù)的侵入較大和業(yè)務(wù)緊耦合,需要根據(jù)特定的場景和業(yè)務(wù)邏輯來設(shè)計相應(yīng)的操作。
還有一點要注意,撤銷和確認(rèn)操作的執(zhí)行可能需要重試,因此還需要保證操作的冪等。
相對于 2PC、3PC ,TCC 適用的范圍更大,但是開發(fā)量也更大,畢竟都在業(yè)務(wù)上實現(xiàn),而且有時候你會發(fā)現(xiàn)這三個方法還真不好寫。不過也因為是在業(yè)務(wù)上實現(xiàn)的,所以TCC可以跨數(shù)據(jù)庫、跨不同的業(yè)務(wù)系統(tǒng)來實現(xiàn)事務(wù)。
本地消息表
本地消息表其實就是利用了 各系統(tǒng)本地的事務(wù)來實現(xiàn)分布式事務(wù)。
本地消息表顧名思義就是會有一張存放本地消息的表,一般都是放在數(shù)據(jù)庫中,然后在執(zhí)行業(yè)務(wù)的時候 將業(yè)務(wù)的執(zhí)行和將消息放入消息表中的操作放在同一個事務(wù)中,這樣就能保證消息放入本地表中業(yè)務(wù)肯定是執(zhí)行成功的。
然后再去調(diào)用下一個操作,如果下一個操作調(diào)用成功了好說,消息表的消息狀態(tài)可以直接改成已成功。
如果調(diào)用失敗也沒事,會有 后臺任務(wù)定時去讀取本地消息表,篩選出還未成功的消息再調(diào)用對應(yīng)的服務(wù),服務(wù)更新成功了再變更消息的狀態(tài)。
這時候有可能消息對應(yīng)的操作不成功,因此也需要重試,重試就得保證對應(yīng)服務(wù)的方法是冪等的,而且一般重試會有最大次數(shù),超過最大次數(shù)可以記錄下報警讓人工處理。
可以看到本地消息表其實實現(xiàn)的是最終一致性,容忍了數(shù)據(jù)暫時不一致的情況。
消息事務(wù)RocketMQ 就很好的支持了消息事務(wù),讓我們來看一下如何通過消息實現(xiàn)事務(wù)。
第一步先給 Broker 發(fā)送事務(wù)消息即半消息,半消息不是說一半消息,而是這個消息對消費者來說不可見,然后發(fā)送成功后發(fā)送方再執(zhí)行本地事務(wù)。
再根據(jù)本地事務(wù)的結(jié)果向 Broker 發(fā)送 Commit 或者 RollBack 命令。
并且 RocketMQ 的發(fā)送方會提供一個反查事務(wù)狀態(tài)接口,如果一段時間內(nèi)半消息沒有收到任何操作請求,那么 Broker 會通過反查接口得知發(fā)送方事務(wù)是否執(zhí)行成功,然后執(zhí)行 Commit 或者 RollBack 命令。
如果是 Commit 那么訂閱方就能收到這條消息,然后再做對應(yīng)的操作,做完了之后再消費這條消息即可。
如果是 RollBack 那么訂閱方收不到這條消息,等于事務(wù)就沒執(zhí)行過。
可以看到通過 RocketMQ 還是比較容易實現(xiàn)的,RocketMQ 提供了事務(wù)消息的功能,我們只需要定義好事務(wù)反查接口即可。
可以看到消息事務(wù)實現(xiàn)的也是最終一致性。
最大努力通知
其實我覺得本地消息表也可以算最大努力,事務(wù)消息也可以算最大努力。
就本地消息表來說會有后臺任務(wù)定時去查看未完成的消息,然后去調(diào)用對應(yīng)的服務(wù),當(dāng)一個消息多次調(diào)用都失敗的時候可以記錄下然后引入人工,或者直接舍棄。這其實算是最大努力了。
事務(wù)消息也是一樣,當(dāng)半消息被commit了之后確實就是普通消息了,如果訂閱者一直不消費或者消費不了則會一直重試,到最后進(jìn)入死信隊列。其實這也算最大努力。
所以最大努力通知其實只是表明了一種柔性事務(wù)的思想:我已經(jīng)盡力我最大的努力想達(dá)成事務(wù)的最終一致了。
適用于對時間不敏感的業(yè)務(wù),例如短信通知。
可以看出 2PC 和 3PC 是一種強(qiáng)一致性事務(wù),不過還是有數(shù)據(jù)不一致,阻塞等風(fēng)險,而且只能用在數(shù)據(jù)庫層面。
而 TCC 是一種補償性事務(wù)思想,適用的范圍更廣,在業(yè)務(wù)層面實現(xiàn),因此對業(yè)務(wù)的侵入性較大,每一個操作都需要實現(xiàn)對應(yīng)的三個方法。
本地消息、事務(wù)消息和最大努力通知其實都是最終一致性事務(wù),因此適用于一些對時間不敏感的業(yè)務(wù)。
看完上述內(nèi)容,你們掌握怎么解析分布式事務(wù)的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!