令人頭疼的分布式事務(wù),一次講明白!
前言
分布式的 CAP 理論應(yīng)該是人盡皆知了,它描述了一致性(C)、可用性(A)、分區(qū)容錯(cuò)性(P)的一系列權(quán)衡。
很多時(shí)候,我們要在一致性和可用性之間權(quán)衡,而分布式事務(wù),就是在這個(gè)大的前提下,盡可能的達(dá)成一致性的要求。
目標(biāo)很小,問(wèn)題很大,做法也各有不同。
“如何在微服務(wù)中實(shí)現(xiàn)分布式事務(wù)?”一般在被問(wèn)到這樣的問(wèn)題時(shí),我都會(huì)回答“要盡量避免使用分布式事務(wù)”,這也是 Martin Fowler 所推薦的。
但現(xiàn)實(shí)總是殘酷的,拆分了微服務(wù)之后,分布式事務(wù)是非常硬核的需求,是繞不開的,我們依然要想辦法搞定它。
但分布式環(huán)境錯(cuò)綜復(fù)雜,還伴隨著網(wǎng)絡(luò)狀況產(chǎn)生的超時(shí),如何讓事務(wù)達(dá)到一致性的狀態(tài),難度很大。
分布式事務(wù),由一系列小的子事務(wù)組成。這些子事務(wù),同大的分布式事務(wù)一樣,同樣要遵循 ACID 的原則。
在一致性這個(gè)屬性上,根據(jù)達(dá)到一致性之前所存在的時(shí)間,又分為強(qiáng)一致性和最終一致性(BASE)。
注意,對(duì)于子事務(wù),這里有個(gè)小小的誤解。并不是只有和數(shù)據(jù)庫(kù)打交道的操作,才叫做事務(wù)。
在微服務(wù)環(huán)境下,如果你通過(guò) RPC 調(diào)用了另外一個(gè)遠(yuǎn)程接口,并造成了相關(guān)數(shù)據(jù)狀態(tài)的變化,這個(gè) RPC 接口,也叫做事務(wù)。
所以,在分布式事務(wù)中,我們把這些子事務(wù)涉及到的操作,叫做資源。當(dāng)操作能正常完成的時(shí)候,根本不需要什么額外處理。事務(wù)主要處理的是發(fā)生異常之后的流程。
下面,我們就來(lái)看一下常見(jiàn)的分布式事務(wù)解決方案。
一階段提交(1PC)
先來(lái)看一下最簡(jiǎn)單的事務(wù)提交情況。
如果你的業(yè)務(wù),只有一個(gè)資源需要協(xié)調(diào),那么它可以直接提交。比如,你使用了一個(gè)數(shù)據(jù)庫(kù),那么就可以直接使用 begin,commit 等指令完成事務(wù)提交。
在 Spring 中,通過(guò)注解,就可以完成這樣的事務(wù)。如果發(fā)生了嵌套事務(wù),它的實(shí)現(xiàn)方式,本質(zhì)上,是通過(guò) ThreadLocal 向下傳遞的。所以如果你的應(yīng)用中有子線程相關(guān)的事務(wù)需要管理,它辦不到。
我們?cè)賮?lái)看分布式事務(wù)。所謂的分布式事務(wù),就是協(xié)調(diào) 2 個(gè)或者多個(gè)資源,達(dá)到共同提交或者共同失敗的效果,也就是分布式的 ACID。
兩階段提交(2PC)
在一階段提交的概念擴(kuò)展下,最簡(jiǎn)單的分布式事務(wù)解決方案,就是二階段提交。二階段提交不是指有兩個(gè)參與資源,而是說(shuō)有兩個(gè)分布式的協(xié)調(diào)階段,它可能有多個(gè)資源需要協(xié)調(diào)。
| 重要參與者
如下:
- 協(xié)調(diào)者(coordinator),也就是我們需要自建事務(wù)管理器,通常在整個(gè)系統(tǒng)中只有一個(gè)
- 事務(wù)參與者(participants),就是指的我們所說(shuō)的資源,通常情況下會(huì)有多個(gè),否則也稱不上分布式事務(wù)了
| 過(guò)程
廣義上的 2PC(two phase commit),有哪兩階段呢?
- client 分布式事務(wù)發(fā)起者
- commit-request/voting 準(zhǔn)備階段
- commit/rollback 提交或者回滾

準(zhǔn)備階段,也叫做 voting 階段。所謂的 voting,就是參與者告知協(xié)調(diào)者,自己的資源到底是能夠提交(代表它準(zhǔn)備好了),還是取消本次事務(wù)(比如發(fā)生異常)。
這個(gè)投票比較有意思,只要有一個(gè)參與者返回了 false,本次事務(wù)就需要終止,然后執(zhí)行 rollback。只有全票通過(guò),才會(huì)正常 commit。協(xié)調(diào)者將這個(gè)結(jié)果,周知所有參與者的這個(gè)過(guò)程,就是二階段。
二階段提交其實(shí)非常容易理解。你可以把每個(gè)參與者的執(zhí)行,想象成正常的 SQL 更新語(yǔ)句。
它們一直掛在那里等待,直到協(xié)調(diào)者給出確切的 commit 或者 rollback 消息,才會(huì)正常往下執(zhí)行。
| 問(wèn)題
如下:
- 阻塞問(wèn)題。 兩階段提交最大的問(wèn)題,就是它是一個(gè)阻塞的協(xié)議,效率低。如果協(xié)調(diào)器永久失敗,一些參與者,將永遠(yuǎn)無(wú)法完成它的事務(wù)
- 單點(diǎn)故障問(wèn)題。 由于協(xié)調(diào)者在整個(gè)環(huán)節(jié)中有著非常重要的作用,所以一旦它發(fā)生了 SPOF,整個(gè)系統(tǒng)將變的不可用,這是不能忍受的
- 事務(wù)完整性問(wèn)題。 在某些情況下,比如協(xié)調(diào)者發(fā)送 commit 指令后,發(fā)生異常,有一部分執(zhí)行成功了,會(huì)造成整個(gè)事務(wù)不一致。因?yàn)槟懿荒芴峤唬谝浑A段就決定了,第二階段只是通知而已,你就是死也要給我提交
- 并不是所有的資源都支持 2PC(或者 XA)
對(duì)于第三點(diǎn),我們舉個(gè)例子。比如你的 commit-request 階段全部返回了 yes,然后協(xié)調(diào)者發(fā)送了 commit 指令。
但這時(shí)候,有一臺(tái)服務(wù)器 A 宕機(jī)了,無(wú)法執(zhí)行這個(gè) commit。這時(shí)候,我們的 client 也會(huì)收到成功的消息。
A 機(jī)器重啟之后,要有能力來(lái)恢復(fù)、繼續(xù)執(zhí)行 commit 指令,這些都是工程上必須要處理的。
| 框架
2PC 也叫做 XA 事務(wù),大多數(shù)數(shù)據(jù)庫(kù)如 MySQL,都支持 XA 協(xié)議。在 Java 中,JTA(不是什么 JPA 哦)是 XA 協(xié)議的實(shí)現(xiàn)。
Spring 也有 JTA 的事務(wù)管理器:
- Atomikos、bitronix 實(shí)現(xiàn)了 JTA,它們只需要提供 jar 包就可以了。實(shí)現(xiàn)了 XA 協(xié)議的數(shù)據(jù)庫(kù)或者消息隊(duì)列,已經(jīng)能夠具備了準(zhǔn)備、提交、回滾的各種能力
- 使用在 seata 等框架,需要啟動(dòng)一個(gè)獨(dú)立的 seata 服務(wù)協(xié)調(diào)者節(jié)點(diǎn)。seata 使用的 AT,借助于外部事務(wù)管理器,概念與 XA 類似
三階段提交(3PC)
相比較二階段提交,三階段提交最典型的特點(diǎn)是加入了超時(shí)機(jī)制。當(dāng)然,3 階段證明了它有三個(gè)階段,這個(gè)差別更顯著。它本質(zhì)上只是 2PC 的一些改進(jìn),所以身上完全充滿了 2PC 的影子。
| 重要參與者
3PC 和 2PC 是一樣的。
| 過(guò)程
3PC 比 2PC 多了一個(gè)步驟,那就是詢問(wèn)階段:
- CanCommit 詢問(wèn)階段
- PreCommit 準(zhǔn)備階段
- DoCommit 提交階段

提交階段,無(wú)非就是發(fā)送個(gè) commit 或者 rollback 指令,重要的處理還是在準(zhǔn)備階段,3PC 把它一拆為 2。
注意下面這個(gè)對(duì)應(yīng)關(guān)系哦,2PC 和 3PC 都有一個(gè)準(zhǔn)備階段,但它們的作用是不同的。
3PC 2PC
CanCommit commit-request/voting
PreCommit
DoCommit commit
3PC 的詢問(wèn)階段,對(duì)應(yīng)的才是 2PC 的準(zhǔn)備階段,都是 ask 一下參與者是否準(zhǔn)備好了,但執(zhí)行過(guò)程會(huì)有一些區(qū)別。
為什么要這么做?因?yàn)?2PC 有效率問(wèn)題。2PC 的執(zhí)行過(guò)程是阻塞的,一個(gè)資源在進(jìn)入準(zhǔn)備階段之后,必須等待所有的資源準(zhǔn)備完畢才能進(jìn)行下一步,在這個(gè)過(guò)程中,它們對(duì)全局一無(wú)所知。
比如,有 ABCDE 等 5 個(gè)參與者,E 其實(shí)是一個(gè)有問(wèn)題的參與者資源。但 2PC 每次都會(huì)執(zhí)行 ABCD 的預(yù)提交,當(dāng)詢問(wèn)到 E 的時(shí)候,發(fā)現(xiàn)是有問(wèn)題的,再依次執(zhí)行 ABCD 等參與者的 rollback。
在這種情況下,ABCD 執(zhí)行了無(wú)用的事務(wù)預(yù)處理和 rollback,是非常浪費(fèi)資源的。
3PC 通過(guò)拆分這個(gè)詢問(wèn)階段,在確保所有參與者建康良好的情況下,才會(huì)發(fā)起真正的事務(wù)處理,在效率和容錯(cuò)性上更勝一籌。
從概率上來(lái)講,由于 commit 之前粒度變小了,commit 階段出問(wèn)題的幾率就變小,能省下不少事。
另外,3PC 引入了超時(shí)機(jī)制。在 PreCommit 階段,如果超時(shí),就認(rèn)為失敗;而在 DoCommit 階段,如果超時(shí)還會(huì)繼續(xù)執(zhí)行下去。但不論怎樣,整個(gè)事務(wù)并不會(huì)一直等待下去。
| 問(wèn)題
3PC 理論上是比較優(yōu)秀的,還能夠避免阻塞問(wèn)題,但它多了一次網(wǎng)絡(luò)通信。如果參與者的數(shù)量比較多,網(wǎng)絡(luò)質(zhì)量比較差的情況下,這個(gè)開銷非??捎^。它的實(shí)現(xiàn)也比較復(fù)雜,在實(shí)際應(yīng)用中,是不太多的。
3PC 也并不是完美的,因?yàn)?PreCommit 階段和 DoCommit 也并不是原子的,和 2PC 類似,依然存在一致性問(wèn)題。
TCC
TCC 是柔性事務(wù),而上面介紹的都是剛性事務(wù)。有時(shí)候,一個(gè)技術(shù)問(wèn)題,可以通過(guò)業(yè)務(wù)建模來(lái)實(shí)現(xiàn)。
2PC 和 3PC 在概念上看起來(lái)雖然簡(jiǎn)單,但放在分布式環(huán)境中,考慮各種超時(shí)和宕機(jī)問(wèn)題,如果考慮的周全,那可真是要了老命。
2PC 的框架還是比較多的,但 3PC 全網(wǎng)找了個(gè)遍,發(fā)現(xiàn)有名的實(shí)現(xiàn)幾乎沒(méi)有。
不要傷心,我們有更容易理解,更加直觀的分布式事務(wù)。那就是 TCC,2007 年的老古董。
TCC 就是大名鼎鼎的補(bǔ)償事務(wù),是互聯(lián)網(wǎng)環(huán)境最常用的分布式事務(wù)。它的核心思想是:為每一個(gè)操作,都準(zhǔn)備一個(gè)確認(rèn)動(dòng)作和相應(yīng)的補(bǔ)償動(dòng)作,一共 3 個(gè)方法。
與其靠數(shù)據(jù)庫(kù),不如靠自己的代碼!2PC,3PC,都和數(shù)據(jù)庫(kù)綁的死死的,TCC 才是碼農(nóng)的最愛(ài)(意思就是說(shuō),你要多寫代碼)。

如上圖,TCC 同樣分為三個(gè)階段,但非常的粗暴:
- try 嘗試階段:嘗試鎖定資源
- confirm 確認(rèn)階段:嘗試將鎖定的資源進(jìn)行提交
- cancel 取消階段:其中某個(gè)環(huán)節(jié)執(zhí)行失敗,將發(fā)起事務(wù)取消動(dòng)作
看起來(lái)這三個(gè)階段,是2階段提交的一種?完全不是。但它們的過(guò)程可以比較一下。
TCC 2PC
Try 業(yè)務(wù)邏輯
Confirm commit-request/voting + commit
Cancel rollback
從上面可以看出來(lái),2PC 是一種對(duì)事務(wù)過(guò)程的劃分,而 TCC 是對(duì)正常情況的提交和異常情況的補(bǔ)償。
相對(duì)于傳統(tǒng)的代碼,try 和 confirm 兩者加起來(lái),才是真正的業(yè)務(wù)邏輯。
TCC 是非常容易理解的,但它有一個(gè)大的前提,就是這三個(gè)動(dòng)作必須都是冪等的,對(duì)業(yè)務(wù)有一定的要求。
拿資金轉(zhuǎn)賬來(lái)說(shuō),try 就是凍結(jié)金額;confirm 就是完成扣減;cancel 就是解凍,只要對(duì)應(yīng)的訂單號(hào)是一直的,多次執(zhí)行也不會(huì)有任何問(wèn)題。
由于 TCC 事務(wù)的發(fā)起方,直接在業(yè)務(wù)節(jié)點(diǎn)即可完成,和 TCC 的代碼在同一個(gè)地方。
所以,TCC 并不需要一個(gè)額外的協(xié)調(diào)者和事務(wù)處理器,它存放在本地表或者資源中即可。
是的,它也要記錄一些信息,哪怕是 HashMap 里,否則它根據(jù)啥回滾呢?
| 問(wèn)題
TCC 事務(wù),需要較多的編碼,以及正確的 try 和 confirm 劃分。由于沒(méi)有中心協(xié)調(diào)器,不需要阻塞,TCC 的并發(fā)量較高,被互聯(lián)網(wǎng)業(yè)務(wù)廣泛應(yīng)用。
團(tuán)隊(duì)要有能力設(shè)計(jì) TCC 接口,將其拆分成正確的 Try 和 Confirm 階段,實(shí)現(xiàn)業(yè)務(wù)邏輯的分級(jí)。
| 框架
ByteTCC、tcc-transaction、seata 等。
SAGA
SAGA 也是一個(gè)柔性事務(wù)。saga 的歷史更久遠(yuǎn),要追溯到 1987 年的一篇論文,可以說(shuō)是瓶舊酒。它主要處理的是長(zhǎng)活事務(wù),但它不保證 ACID,只保證最終一致性。
所謂長(zhǎng)活事務(wù),可以被分解成交錯(cuò)運(yùn)行的子事務(wù),它通過(guò)消息,來(lái)協(xié)調(diào)一系列的本地子事務(wù),來(lái)達(dá)到最終的一致性。
我們可以把 SAGA 編排器,想象成一個(gè)狀態(tài)機(jī)。每當(dāng)處理完一條消息,它就能夠知道要執(zhí)行的下一條消息(子事務(wù))。
比如,我們把事務(wù) T,拆分成了 T1,T2,T3,T4。那么我們就必須為這些子事務(wù),提供相應(yīng)的執(zhí)行邏輯和補(bǔ)償邏輯。
沒(méi)錯(cuò),和 TCC 一樣,不過(guò)比 TCC 少了一步 Try 動(dòng)作,同樣要求這些操作是冪等的。
你瞧瞧,其實(shí) SAGA 的概念很好理解,你就按照正常的業(yè)務(wù)邏輯去執(zhí)行就行了。只不過(guò)如果在任何一步發(fā)生了異常,就要把前面所提交的數(shù)據(jù)全部回滾(補(bǔ)償)。唯一特殊的是,它通常是通過(guò)消息驅(qū)動(dòng)來(lái)完成事務(wù)運(yùn)轉(zhuǎn)的。
如果你非要追求它的本質(zhì),那就是 SAGA 和 TCC 一樣,都是先記錄執(zhí)行軌跡,然后通過(guò)不斷地重試達(dá)到最終狀態(tài)。

上圖是 rob vettor 所繪制的一個(gè)典型的 SAGA 事務(wù)拆分圖。在圖中,黑色的線為正常業(yè)務(wù)流程,紅色的線為補(bǔ)償業(yè)務(wù)流程。
這是一個(gè)簡(jiǎn)單的電子商務(wù)結(jié)賬流程,整個(gè)交易跨了 5 個(gè)微服務(wù),可以說(shuō)是非常大的長(zhǎng)事務(wù)了。
可以看到,這樣的事務(wù)流轉(zhuǎn),靠文字描述已經(jīng)是不好理解了,所以 SAGA 通常會(huì)配備一個(gè)流程編輯器,直接來(lái)把事務(wù)編排的過(guò)程可視化。
| 問(wèn)題
那問(wèn)題就有意思多了:
- 嵌套問(wèn)題。 SAGA 只允許兩層嵌套,因?yàn)榭肯⒘鬓D(zhuǎn)本來(lái)就非常復(fù)雜了,嵌套層次深在性能和時(shí)序上都不允許
- 如果你的事務(wù)包含很多子事務(wù),那么很有可能在某個(gè)階段就執(zhí)行失敗了。但如果補(bǔ)償操作也發(fā)生問(wèn)題了呢?極端情況下,需要人工參與。在很多時(shí)候,需要記錄日志(saga log)來(lái)配合完成
- 由于這些小事務(wù)并不是同時(shí)提交的,所以在執(zhí)行的過(guò)程中,會(huì)產(chǎn)生臟數(shù)據(jù),這和數(shù)據(jù)庫(kù)的 read uncommited 的概念是一樣的
| 框架
在《微服務(wù)架構(gòu)設(shè)計(jì)模式》的第四章中,說(shuō)明了 SAGA 的具體使用示例,現(xiàn)在網(wǎng)絡(luò)上的大多數(shù)文章都來(lái)自于此。
但據(jù)我所知,使用 SAGA 的互聯(lián)網(wǎng)公司并不是很多,倒是使用 TCC 的比較多一些(可能是遇到的分布式事務(wù)都不是長(zhǎng)事務(wù))。
seata 同樣提供了 SAGA 的方式,主要使用的是狀態(tài)機(jī)驅(qū)動(dòng)的編排模式。為了支持事務(wù)的編排,seata 提供了一個(gè)專用的流程編輯器(在線)。
http://seata.io/saga_designer/index.html
設(shè)計(jì)完畢之后,就可以導(dǎo)出為 JSON 文件,解析之后可以寫入到數(shù)據(jù)庫(kù)中。bytetcc 雖然叫 tcc,它也支持 SAGA。
| SAGA vs TCC
上面也提到,我在平常工作中,用到 TCC 比 SAGA 更多一些,也是由于業(yè)務(wù)場(chǎng)景確定的。
下面簡(jiǎn)單的對(duì)比一下:
- 開發(fā)難度。 TCC 的開發(fā)難度是比 SAGA 要高的,因?yàn)樗枰幚?Try 階段來(lái)凍結(jié)資源,而 SAGA 是直接執(zhí)行本地事務(wù)
- 臟讀問(wèn)題。 TCC 不存在臟讀,因?yàn)?try 階段并不影響數(shù)據(jù);SAGA 會(huì)在小事務(wù)之間,或者 cancel 之間出現(xiàn)臟讀
- 效率問(wèn)題。TCC 無(wú)論成功失敗,都需要和參與方交互兩次;SAGA 在正常情況下交互一次,異常情況下交互兩次,所以效率要高
- 業(yè)務(wù)流程。 TCC 適合少量的分布式事務(wù)流程,否則寫起來(lái)就是噩夢(mèng);SAGA 適合業(yè)務(wù)流程長(zhǎng),參與方多的業(yè)務(wù),或者遺留系統(tǒng)等無(wú)法改造成 TCC 的業(yè)務(wù)
- 手段。 TCC 是通過(guò)業(yè)務(wù)建模手段解決技術(shù)問(wèn)題;SAGA 是通過(guò)技術(shù)手段解決事務(wù)編排
本地消息表
本地消息表的使用場(chǎng)景比較局限,它要靠 MQ 去實(shí)現(xiàn),它解決的是數(shù)據(jù)庫(kù)事務(wù)和 MQ 之間的事務(wù)問(wèn)題。

如圖,有一個(gè)分布式事務(wù),在正常落庫(kù)之后,需要通過(guò) MQ 來(lái)協(xié)調(diào)后續(xù)業(yè)務(wù)的執(zhí)行。但是,寫 DB 和寫 MQ,是無(wú)法達(dá)成一致性的,就需要加入一個(gè)本地消息表來(lái)緩存發(fā)送到 MQ 的狀態(tài)。
下面我來(lái)描述一下這個(gè)過(guò)程:
- 正常寫入數(shù)據(jù)庫(kù),在寫入數(shù)據(jù)庫(kù)的同時(shí),寫入一張本地消息表。這張表,用來(lái)記錄 MQ 消息處理的狀態(tài),可以有發(fā)送中和已完成兩種狀態(tài)。由于消息表和正常的業(yè)務(wù)表在一個(gè) DB 中,所以可以達(dá)成本地事務(wù),確保同時(shí)完成
- 寫入消息表成功之后,可以異步發(fā)送 MQ 消息,且不用關(guān)心投遞是否成功
- 后續(xù)業(yè)務(wù)訂閱 MQ 消息。消費(fèi)成功之后,將會(huì)把執(zhí)行成功的狀態(tài),再通過(guò) MQ 來(lái)發(fā)送。本地業(yè)務(wù)訂閱這個(gè)執(zhí)行狀態(tài),并把消息表中對(duì)應(yīng)的記錄狀態(tài),改為已完成;如果消費(fèi)失敗,則不做過(guò)多處理
- 存在一個(gè)定時(shí)任務(wù),持續(xù)掃描本地消息表中,狀態(tài)為發(fā)送中的消息(注意延時(shí)),并再次把這些消息發(fā)送到 MQ,重復(fù) 2 的過(guò)程
通過(guò)這樣的循環(huán),就可以達(dá)到本地 DB 和 MQ 消費(fèi)者狀態(tài)的一致性,完成最終一致性的分布式事務(wù)。
可以看到,我們有重發(fā) MQ 的過(guò)程,所以這種模式要求消費(fèi)者也要實(shí)現(xiàn)冪等的功能,避免重復(fù)對(duì)業(yè)務(wù)產(chǎn)生影響。
| 問(wèn)題
使用本地消息表方案的系統(tǒng)還是挺多的,但它的弊端也顯而易見(jiàn):
- 需要開發(fā)專用的代碼,與業(yè)務(wù)耦合在一起,無(wú)法完成抽象的框架
- 本地消息表需要寫數(shù)據(jù)庫(kù),如果數(shù)據(jù)庫(kù)本身的 I/O 已經(jīng)比較高了,它會(huì)增加數(shù)據(jù)庫(kù)的壓力
最大努力補(bǔ)償
最大努力補(bǔ)償,是一種衰減式的補(bǔ)償機(jī)制。
拿個(gè)最簡(jiǎn)單的例子來(lái)說(shuō)吧。如果你是微信支付的接入方,微信支付成功之后,它會(huì)將支付結(jié)果推送到你指定的接口。
微信支付+你的支付結(jié)果處理,就可以算是一個(gè)大的分布式事務(wù)。涉及到微信的系統(tǒng)還有你的自有系統(tǒng)。
如果你的系統(tǒng)一直處理不成功,那么微信支付就會(huì)一直不停的重試。這就叫最大努力補(bǔ)償,用在系統(tǒng)內(nèi)和系統(tǒng)間都是可以的。
但也不能無(wú)限的重試,重試的間隔通常會(huì)隨著時(shí)間衰減。常用的衰減策略有。
messageDelayLevel = 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
上面的公式,意味著如果一直無(wú)法處理成功,將在 1s...,最大 2 小時(shí)后重試。如果還不成功,就只能進(jìn)入人工處理通道。
最大努力補(bǔ)償只是一種思想,實(shí)際的應(yīng)用有多種方式。比如,我首先將事務(wù)落地到消息隊(duì)列,然后依靠消息隊(duì)列的重試機(jī)制,來(lái)達(dá)到最大努力補(bǔ)償?shù)男Ч?,這些都是可行的方案。
總結(jié)
我們?cè)谖闹?,從本地事?wù)談起,分別聊到了 2PC、3PC、TCC、SAGA、本地消息表、最大努力補(bǔ)償?shù)龋擦私獾搅烁鞣N解決方案的一些應(yīng)用場(chǎng)景和解決方式。
分布式事務(wù)框架,在這些理論基礎(chǔ)上,都進(jìn)行了或多或少的修訂,也有不少創(chuàng)新。比如 LCN 框架(lock,confirm,notify),就抽象出了控制方和發(fā)起方的概念,感興趣的可以自行了解。
在互聯(lián)網(wǎng)公司中,由于高并發(fā)量的訴求,在實(shí)際應(yīng)用中,相對(duì)于強(qiáng)事務(wù),大家普遍選用軟事務(wù)進(jìn)行業(yè)務(wù)處理。 使用最多的,就是 TCC、SAGA、本地消息表等解決方案。
SAGA 應(yīng)對(duì)長(zhǎng)事務(wù)特別拿手,但隔離性稍差; TCC 一直性好并發(fā)高,但需要較多編碼; 本地消息表應(yīng)用場(chǎng)景有限,耦合業(yè)務(wù)不能復(fù)用。 各種解決方案都有它的利弊,一定要結(jié)合使用場(chǎng)景進(jìn)行選擇。
在框架方面,阿里的 seata(早些年叫 fescar),已經(jīng)得到了廣泛應(yīng)用,XA、TCC、SAGA 等模式都支持,如果你需要這方面的功能,可以集成嘗試一下。
希望看完本文之后,再次碰到“如何在微服務(wù)中實(shí)現(xiàn)分布式事務(wù)?”這種問(wèn)題,除了回答“要盡量避免使用分布式事務(wù)”,你還可以找到確實(shí)可行的解決方案。
























