https://mp.weixin.qq.com/s/cP8JC-KB3rniHAXj39rAHQ (摘自此文)
一個復(fù)雜的系統(tǒng)往往都是從一個小而簡的系統(tǒng)發(fā)展衍化而來,為了滿足日益增長的業(yè)務(wù)需求,
不斷的增加系統(tǒng)的復(fù)雜度,從單體架構(gòu)逐步發(fā)展為分布式架構(gòu),
而分布式系統(tǒng)架構(gòu)的設(shè)計主要關(guān)注:高性能,高可用,高拓展
#一些建議
在實際生產(chǎn)中我們要盡量避免使用分布式事務(wù),能轉(zhuǎn)化為本地事務(wù)就用本地事務(wù),
如果必須使用分布式事務(wù),還需要從業(yè)務(wù)角度多思考使用哪種方案更適合
1.分布式事務(wù)
高可用是指系統(tǒng)無中斷的執(zhí)行功能的能力,代表了系統(tǒng)的可用程度,
是進行系統(tǒng)設(shè)計時必須要遵守的準則之一。
而高可用的實現(xiàn)方案,無外乎就是冗余,就存儲的高可用而言,
問題不在于如何進行數(shù)據(jù)備份,而在于如何規(guī)避數(shù)據(jù)不一致對業(yè)務(wù)造成的影響
對于分布式系統(tǒng)而言,要保證分布式系統(tǒng)中的數(shù)據(jù)一致性就需要一種方案,
可以保證數(shù)據(jù)在子系統(tǒng)中始終保持一致,避免業(yè)務(wù)出現(xiàn)問題,
該方案就叫做分布式事務(wù),要么一起成功,要么一起失敗,必須是一個整體性的事務(wù)
1.1 電商中的庫存問題
在電商網(wǎng)站中,用戶對商品進行下單,需要在訂單表中創(chuàng)建一條訂單數(shù)據(jù),
同時需要在庫存表中修改當前商品的剩余庫存數(shù)量,兩步操作一個添加,一個修改,
我們一定要保證這兩步操作一定同時操作成功或失敗,否則業(yè)務(wù)就會出現(xiàn)問題
建立時
業(yè)務(wù)量不大,用戶少,系統(tǒng)只是一個單體架構(gòu),
訂單表與庫存表都在一個數(shù)據(jù)庫中,這時可以使用mysql的本地事務(wù)保證數(shù)據(jù)一致性
發(fā)展期
業(yè)務(wù)發(fā)展迅速,用戶量變多,單數(shù)據(jù)已經(jīng)出現(xiàn)了性能瓶頸,
按照業(yè)務(wù)緯度進行分庫,分為訂單庫和庫存庫,由于跨庫跨機器,
mysql的本地事務(wù)不能再保證訂單庫和庫存庫的數(shù)據(jù)一致性,這時候就需要分布式事務(wù)來保證
成熟期
業(yè)務(wù)拓展,單體架構(gòu)已經(jīng)滿足不了需求,進而衍化成了分布式系統(tǒng),
這時的訂單和庫存已經(jīng)拆分為了兩個子系統(tǒng)提供服務(wù),子系統(tǒng)間使用rpc進行通信,
但是無論系統(tǒng)發(fā)展成什么樣,我們都要保證業(yè)務(wù)不出問題,保證訂單和庫存的數(shù)據(jù)一致,
這時候要思考下在服務(wù)之間我們應(yīng)如何保證數(shù)據(jù)一致
在講解具體方案之前,有必要了解一下分布式中數(shù)據(jù)設(shè)計需要遵循的理論基礎(chǔ)(CAP理論 & BASE理論)
1.2 理論基礎(chǔ)(CAP理論 & BASE理論)
1.2.1 CAP理論
CAP:Consistency Acailability Partition tolerance
CAP理論關(guān)注粒度是[數(shù)據(jù)],而不是整體系統(tǒng)設(shè)計的策略
>> Consistency:
一致性,對某個客戶端來說,讀操作能夠返回最新的寫操作結(jié)果
>> Acailability:
可用性,非故障節(jié)點在合理的時間內(nèi)返回合理的響應(yīng)
>> Partition tolerance:
分區(qū)容錯性,當出現(xiàn)網(wǎng)絡(luò)分區(qū)后,系統(tǒng)能夠繼續(xù)提供服務(wù) 你知道什么是網(wǎng)絡(luò)分區(qū)嗎 ~~
因為分布式系統(tǒng)中系統(tǒng)肯定部署在多臺機器上,無法保證網(wǎng)絡(luò)做到
100%的可靠,所以網(wǎng)絡(luò)分區(qū)一定存在,即P一定存在;
在出現(xiàn)網(wǎng)絡(luò)分區(qū)后,就出現(xiàn)了可用性和一致性的問題,
我們必須要在這兩者之間進行取舍,因此就有了兩種架構(gòu):CP架構(gòu),AP架構(gòu);
CP架構(gòu)
當網(wǎng)絡(luò)分區(qū)出現(xiàn)后,為了保證一致性,就必須拒接請求,否則無法保證一致性

CP架構(gòu)設(shè)計.png
#上圖中
1.當沒有出網(wǎng)絡(luò)分區(qū)時,系統(tǒng)A與系統(tǒng)B的數(shù)據(jù)一致,X=1
2.將系統(tǒng)A的X修改為2,X=2
3.當出現(xiàn)網(wǎng)絡(luò)分區(qū)后,系統(tǒng)A與系統(tǒng)B之間的數(shù)據(jù)同步數(shù)據(jù)失敗,系統(tǒng)B的X=1
4.當客戶端請求系統(tǒng)B時,為了保證一致性,此時系統(tǒng)B應(yīng)拒絕服務(wù)請求,返回錯誤碼或錯誤信息
上面這種方式就違背了可用性的要求,只滿足一致性和分區(qū)容錯,即CP
CAP理論是忽略網(wǎng)絡(luò)延遲,從系統(tǒng)A同步數(shù)據(jù)到系統(tǒng)B的網(wǎng)絡(luò)延遲是忽略的
CP架構(gòu)保證了客戶端在獲取數(shù)據(jù)時一定是最近的寫操作,
或者獲取到異常信息,絕不會出現(xiàn)數(shù)據(jù)不一致的情況
AP架構(gòu)
當網(wǎng)絡(luò)分區(qū)出現(xiàn)后,為了保證可用性,系統(tǒng)B可以返回舊值,保證系統(tǒng)的可用性

AP架構(gòu).png
#上圖中
1.當沒有出網(wǎng)絡(luò)分區(qū)時,系統(tǒng)A與系統(tǒng)B的數(shù)據(jù)一致,X=1
2.將系統(tǒng)A的X修改為2,X=2
3.當出現(xiàn)網(wǎng)絡(luò)分區(qū)后,系統(tǒng)A與系統(tǒng)B之間的數(shù)據(jù)同步數(shù)據(jù)失敗,系統(tǒng)B的X=1
4.當客戶端請求系統(tǒng)B時,為了保證可用性,此時系統(tǒng)B應(yīng)返回舊值,X=1
上面這種方式就違背了一致性的要求,只滿足可用性和分區(qū)容錯,即AP
CP架構(gòu)保證了客戶端在獲取數(shù)據(jù)時無論返回的是最新值還是舊值,系統(tǒng)一定是可用的
1.2.2 BASE理論
BASE理論指的是基本可用 Basically Available,軟狀態(tài) Soft Stat,最終一致性 Eventual Consistency,
核心思想是即便無法做到強一致性,但應(yīng)該可以有采用適合的方式保證最終一致性
BASE:Basically Available Soft Stat Eventual Consistency的簡寫
>> BA:Basically Available 基本可用
分布式系統(tǒng)在出現(xiàn)故障的時候,允許損失部分可用性,即保證核心可用
>> S:Soft Stat 軟狀態(tài)
允許系統(tǒng)存在中間狀態(tài),而該中間狀態(tài)不會影響系統(tǒng)整體可用性
>> E:Consistency 最終一致性
系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過一定時間后,最終能夠達到一致的狀態(tài)
BASE理論本質(zhì)上是對CAP理論的延伸,是對 CAP 中 AP 方案的一個補充
2.分布式事務(wù)協(xié)議
#前提:
在單體架構(gòu)中,事務(wù)的保證有mysql實現(xiàn),不用我們實現(xiàn),
當單個數(shù)據(jù)庫的性能出現(xiàn)瓶頸的時候,對數(shù)據(jù)庫進行分表分庫處理,
按業(yè)務(wù)緯度將訂單和庫存的表分為兩個庫,訂單庫和庫存庫
2.1 X/Open XA 協(xié)議
XA是一個分布式事務(wù)協(xié)議,由Tuxedo提出。
XA規(guī)范主要定義了(全局)事務(wù)管理器(Transaction Manager)和
(局部)資源管理器(Resource Manager)之間的接口。
XA接口是雙向的系統(tǒng)接口,在事務(wù)管理器Transaction Manager)
以及一個或多個資源管理器(Resource Manager)之間形成通信橋梁。
XA協(xié)議采用兩階段提交方式來管理分布式事務(wù)。
XA接口提供資源管理器與事務(wù)管理器之間進行通信的標準接口。

X/Open XA 協(xié)議.png
2.2 2PC 二階段提交 協(xié)議
二階段提交(Two-phase Commit)
是為了使基于分布式系統(tǒng)架構(gòu)下的所有節(jié)點在進行事務(wù)提交時保持一致性而設(shè)計的一種算法(Algorithm)。
通常,二階段提交也被稱為是一種協(xié)議(Protocol)。
在分布式系統(tǒng)中,每個節(jié)點雖然可以知曉自己的操作的成功或者失敗,
卻無法知道其他節(jié)點的操作的成功或失敗。
當一個事務(wù)跨越多個節(jié)點時,為了保持事務(wù)的ACID特性,
需要引入一個作為協(xié)調(diào)者的組件來統(tǒng)一掌控所有節(jié)點(稱作參與者)的
操作結(jié)果并最終指示這些節(jié)點是否要把操作結(jié)果進行真正的提交(比如將更新后的數(shù)據(jù)寫入磁盤等等)。
#二階段提交的算法思路可以概括為:
參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。
#二階段提交算法的成立基于以下假設(shè):
1.該分布式系統(tǒng)中,存在一個節(jié)點作為協(xié)調(diào)者(Coordinator),其他節(jié)點作為參與者(Cohorts)。
且節(jié)點之間可以進行網(wǎng)絡(luò)通信。
2.所有節(jié)點都采用預(yù)寫式日志,且日志被寫入后即被保持在可靠的存儲設(shè)備上,
即使節(jié)點損壞不會導(dǎo)致日志數(shù)據(jù)的消失。
3.所有節(jié)點不會永久性損壞,即使損壞后仍然可以恢復(fù)。
#二階段提交分為兩階段
1.第一階段:投票階段
>> 協(xié)調(diào)者向所有參與者詢問是否可以執(zhí)行提交操作,并開始等待各參與者的響應(yīng)
>> 參與者執(zhí)行事務(wù)操作,如果執(zhí)行成功就返回Yes響應(yīng),如果執(zhí)行失敗就返回No響應(yīng)
>> 如果協(xié)調(diào)者接收參與者響應(yīng)超時,也會認為執(zhí)行事務(wù)操作失敗
2.第二階段:提交階段
>> 如果第一階段中所有參與者都返回yes響應(yīng),協(xié)調(diào)者向所有參與者發(fā)出提交請求,所有參與者提交事務(wù)
>> 如果第一階段中有一個或者多個參與者返回no響應(yīng),協(xié)調(diào)者向所有參與者發(fā)出回滾請求,所有參與者進行回滾操作

二階段提交.png

第一階段:投票階段 Prepares.png

第二階段:提交階段 commit.png
#二階段提交優(yōu)點:
盡量保證了數(shù)據(jù)的強一致,但不是100%一致
#缺點:
>> 單點故障:
由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障,參與者會一直阻塞,尤其時在第二階段,
協(xié)調(diào)者發(fā)生故障,那么所有的參與者都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作
>> 同步阻塞:
由于所有節(jié)點在執(zhí)行操作時都是同步阻塞的,當參與者占有公共資源時,
其他第三方節(jié)點訪問公共資源不得不處于阻塞狀態(tài)
>> 數(shù)據(jù)不一致:
在第二階段中,當協(xié)調(diào)者想?yún)⑴c者發(fā)送提交事務(wù)請求之后,
發(fā)生了局部網(wǎng)絡(luò)異?;蛘咴诎l(fā)送提交事務(wù)請求過程中協(xié)調(diào)者發(fā)生了故障,
這會導(dǎo)致只有一部分參與者接收到了提交事務(wù)請求。而在這部分參與者接到提交事務(wù)請求之后就會執(zhí)行提交事務(wù)操作。
但是其他部分未接收到提交事務(wù)請求的參與者則無法提交事務(wù)。
從而導(dǎo)致分布式系統(tǒng)中的數(shù)據(jù)不一致。
#二階段提交的問題
如果協(xié)調(diào)者在第二階段發(fā)送提交請求之后掛掉,而唯一接受到這條消息的參與者執(zhí)行之后也掛掉了,
即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者并通知其他參與者進行提交或回滾操作的話,
都可能會與這個已經(jīng)執(zhí)行的參與者執(zhí)行的操作不一樣,
當這個掛掉的參與者恢復(fù)之后,就會產(chǎn)生數(shù)據(jù)不一致的問題。
2.3 3PC 三階段提交 協(xié)議
三階段提交(Three-phase commit),三階段提交是為解決兩階段提交協(xié)議|的缺點而設(shè)計的。
與兩階段提交不同的是,三階段提交是“非阻塞”協(xié)議。
三階段提交在兩階段提交的第一階段與第二階段之間插入了一個準備階段,
使得原先在兩階段提交中,參與者在投票之后,
由于協(xié)調(diào)者發(fā)生崩潰或錯誤而導(dǎo)致參與者處于無法知曉
是否提交或者中止的“不確定狀態(tài)”所產(chǎn)生的可能相當長的延時的問題得以解決
#三階段提交的三個階段:
1.詢問階段 CanCommit
協(xié)調(diào)者向參與者發(fā)送commit請求,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)
2.準備階段 PreCommit
協(xié)調(diào)者根據(jù)參與者在詢問階段的響應(yīng)判斷是否執(zhí)行事務(wù)還是中斷事務(wù)
>> 如果所有參與者都返回Yes,則執(zhí)行事務(wù)
>> 如果參與者有一個或多個參與者返回No或者超時,則中斷事務(wù)
參與者執(zhí)行完操作之后返回ACK響應(yīng),同時開始等待最終指令
3.提交階段 DoCommit
協(xié)調(diào)者根據(jù)參與者在準備階段的響應(yīng)判斷是否執(zhí)行事務(wù)還是中斷事務(wù)
>> 如果所有參與者都返回正確的ACK響應(yīng),則提交事務(wù)
>> 如果參與者有一個或多個參與者收到錯誤的ACK響應(yīng)或者超時,則中斷事務(wù)
>> 如果參與者無法及時接收到來自協(xié)調(diào)者的提交或者中斷事務(wù)請求時,會在等待超時之后,會繼續(xù)進行事務(wù)提交
協(xié)調(diào)者收到所有參與者的ACK響應(yīng),完成事務(wù)

三階段提交.png
#解決二階段提交時的問題
在三階段提交中,如果在第三階段協(xié)調(diào)者發(fā)送提交請求之后掛掉,
并且唯一的接受的參與者執(zhí)行提交操作之后也掛掉了,這時協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者,
新的協(xié)調(diào)者不確定已經(jīng)執(zhí)行過事務(wù)的參與者是執(zhí)行的提交事務(wù)還是中斷事務(wù),
但是在三階段提交時,肯定得到了第二階段的再次確認,
那么第二階段必然是已經(jīng)正確的執(zhí)行了事務(wù)操作,只等待提交事務(wù)了,
所以新的協(xié)調(diào)者可以從第二階段中分析出應(yīng)該執(zhí)行的操作,進行提交或者中斷事務(wù)操作,
這樣即使掛掉的參與者恢復(fù)過來,數(shù)據(jù)也是一致的。
所以,三階段提交解決了二階段提交中存在的由于協(xié)調(diào)者和參與者同時掛掉
可能導(dǎo)致的數(shù)據(jù)一致性問題和單點故障問題,并減少阻塞,
因為一旦參與者無法及時收到來自協(xié)調(diào)者的信息之后,
他會默認執(zhí)行提交事務(wù),而不會一直持有事務(wù)資源并處于阻塞狀態(tài)。
#三階段提交的問題
在提交階段如果發(fā)送的是中斷事務(wù)請求,但是由于網(wǎng)絡(luò)問題,
導(dǎo)致部分參與者沒有接到請求,那么參與者會在等待超時之后執(zhí)行提交事務(wù)操作,
這樣這些由于網(wǎng)絡(luò)問題導(dǎo)致提交事務(wù)的參與者的數(shù)據(jù)就與接受到中斷事務(wù)請求的參與者存在數(shù)據(jù)不一致的問題。
所以無論是2PC還是3PC都不能保證分布式系統(tǒng)中的數(shù)據(jù)100%一致
3.分布式事務(wù)解決方案
3.1 強一致性分布式事務(wù)
單體架構(gòu)多數(shù)據(jù)源,在業(yè)務(wù)開發(fā)中,肯定是先執(zhí)行對訂單庫的操作,
但是不提交事務(wù),再執(zhí)行對庫存庫的操作,也不提交事務(wù),
如果兩個操作都成功,在一起提交事務(wù),如果有一個操作失敗,則兩個都進行回滾
3.1.1 基于2PC/XA協(xié)議實現(xiàn)的JTA
JTA是java規(guī)范,是XA在java上的實現(xiàn)
#JTA(Java Transaction Manager) :
>> TransactionManager : 常用方法,可以開啟,回滾,獲取事務(wù). begin(),rollback()…
>> XAResouce : 資源管理,通過Session來進行事務(wù)管理,commit(xid)…
>> XID : 每一個事務(wù)都分配一個特定的XID
JTA主要的原理是二階段提交,當整個業(yè)務(wù)完成了之后只是第一階段提交,
在第二階段提交之前會檢查其他所有事務(wù)是否已經(jīng)提交,
如果前面出現(xiàn)了錯誤或是沒有提交,那么第二階段就不會提交,
而是直接回滾,這樣所有的事務(wù)都會做回滾操作
基于JTA這種方案實現(xiàn)分布式事務(wù)的強一致性
#JTA的特點:
>> 基于兩階段提交,有可能會出現(xiàn)數(shù)據(jù)不一致的情況
>> 事務(wù)時間過長,阻塞
>> 性能低,吞吐量低
實現(xiàn)可以使用基于JTA實現(xiàn)的jar包Atomikos
正常架構(gòu)設(shè)計中是否應(yīng)該出現(xiàn)這種跨庫的操作,我覺得是不應(yīng)該的,
如果過按業(yè)務(wù)拆分將數(shù)據(jù)源進行分庫,我們應(yīng)該同時將服務(wù)也拆分出去才合適,
應(yīng)遵循一個系統(tǒng)只操作一個數(shù)據(jù)源(主從沒關(guān)系),避免后續(xù)可能會出現(xiàn)的多個系統(tǒng)調(diào)用一個數(shù)據(jù)源的情況
3.2 最終一致性分布式事務(wù)方案(柔性事務(wù))
JTA方案適用于單體架構(gòu)多數(shù)據(jù)源時實現(xiàn)分布式事務(wù),
但對于微服務(wù)間的分布式事務(wù)就無能為力了,我們需要使用其他的方案實現(xiàn)分布式事務(wù)
3.2.1 本地消息表
本地消息表的核心思想是將分布式事務(wù)拆分成本地事務(wù)進行處理。
以本文中例子,在訂單系統(tǒng)新增一條消息表,將新增訂單和新增消息放到一個事務(wù)里完成,
然后通過輪詢的方式去查詢消息表,將消息推送到mq,庫存系統(tǒng)去消費mq。
#執(zhí)行流程:
>> 訂單系統(tǒng),添加一條訂單和一條消息,在一個事務(wù)里提交
>> 訂單系統(tǒng),使用定時任務(wù)輪詢查詢狀態(tài)為未同步的消息表,發(fā)送到mq,如果發(fā)送失敗,就重試發(fā)送
>> 庫存系統(tǒng),接收mq消息,修改庫存表,需要保證冪等操作
>> 如果修改成功,調(diào)用rpc接口修改訂單系統(tǒng)消息表的狀態(tài)為已完成或者直接刪除這條消息
>> 如果修改失敗,可以不做處理,等待重試
#這其中需要注意的地方
>> 訂單系統(tǒng)中的消息有可能由于業(yè)務(wù)問題會一直重復(fù)發(fā)送,
所以為了避免這種情況可以記錄一下 發(fā)送次數(shù),當達到次數(shù)限制之后報警,人工接入處理;
>> 庫存系統(tǒng)需要保證冪等,避免同一條消息被多次消費造成數(shù)據(jù)一致;
#問題
本地消息表這種方案實現(xiàn)了最終一致性,需要在業(yè)務(wù)系統(tǒng)里增加消息表,
業(yè)務(wù)邏輯中多一次插入的DB操作,所以性能會有損耗,
而且最終一致性的間隔主要由定時任務(wù)的間隔時間決定。

本地消息表.png
3.2.2 MQ消息事務(wù)
消息事務(wù)的原理是將兩個事務(wù)通過消息中間件進行異步解耦。
#例子
訂單系統(tǒng)執(zhí)行自己的本地事務(wù),并發(fā)送mq消息,庫存系統(tǒng)接收消息,執(zhí)行自己的本地事務(wù),
消息事務(wù)一定要保證業(yè)務(wù)操作與消息發(fā)送的一致性,如果業(yè)務(wù)操作成功,這條消息也一定投遞成功
#原理
消息事務(wù)依賴于消息中間件的事務(wù)消息,基于消息中間件的二階段提交實現(xiàn)的,RocketMQ就支持事務(wù)消息
#執(zhí)行流程:
>> 發(fā)送prepare消息到消息中間件
>> 發(fā)送成功后,執(zhí)行本地事務(wù)
>> 如果事務(wù)執(zhí)行成功,則commit,消息中間件將消息下發(fā)至消費端
>> 如果事務(wù)執(zhí)行失敗,則回滾,消息中間件將這條prepare消息刪除
>> 消費端接收到消息進行消費,如果消費失敗,則不斷重試
這種方案也是實現(xiàn)了最終一致性,對比本地消息表實現(xiàn)方案,
不需要再建消息表,不再依賴本地數(shù)據(jù)庫事務(wù)了,所以這種方案更適用于高并發(fā)的場景

MQ消息事務(wù).png
3.2.3 最大努力通知
最大努力通知相比前兩種方案實現(xiàn)簡單,
適用于一些最終一致性要求較低的業(yè)務(wù),比如支付通知,短信通知這種業(yè)務(wù)
#以支付通知為例
業(yè)務(wù)系統(tǒng)調(diào)用支付平臺進行支付,支付平臺進行支付,
進行操作支付之后支付平臺會盡量去通知業(yè)務(wù)系統(tǒng)支付操作是否成功,
但是會有一個最大通知次數(shù),如果超過這個次數(shù)后還是通知失敗,就不再通知,
業(yè)務(wù)系統(tǒng)自行調(diào)用支付平臺提供一個查詢接口,供業(yè)務(wù)系統(tǒng)進行查詢支付操作是否成功
#執(zhí)行流程:
>> 業(yè)務(wù)系統(tǒng)調(diào)用支付平臺支付接口,并在本地進行記錄,支付狀態(tài)為支付中
>> 支付平臺進行支付操作之后,無論成功還是失敗,都需要給業(yè)務(wù)系統(tǒng)一個結(jié)果通知
>> 如果通知一直失敗則根據(jù)重試規(guī)則進行重試,達到最大通知次數(shù)后,不再通知
>> 支付平臺提供查詢訂單支付操作結(jié)果接口
>> 業(yè)務(wù)系統(tǒng)根據(jù)一定業(yè)務(wù)規(guī)則去支付平臺查詢支付結(jié)果
3.2.4 補償事務(wù)TCC
#TCC(Try-Confirm-Cancel)
針對每個操作,都需要有一個其對應(yīng)的確認和取消操作,
當操作成功時調(diào)用確認操作,當操作失敗時調(diào)用取消操作,
類似于二階段提交,只不過是這里的提交和回滾是針對業(yè)務(wù)上的,
所以基于TCC實現(xiàn)的分布式事務(wù)也可以看做是對業(yè)務(wù)的一種補償機制
#TCC的三階段:
1.Try 階段:
對業(yè)務(wù)系統(tǒng)做檢測及資源預(yù)留
2.Confirm 階段:
對業(yè)務(wù)系統(tǒng)做確認提交,Try階段執(zhí)行成功并開始執(zhí)行 Confirm階段時,默認 Confirm階段是不會出錯的。
即:只要Try成功,Confirm一定成功。
3.Cancel 階段:
在業(yè)務(wù)執(zhí)行錯誤,需要回滾的狀態(tài)下執(zhí)行的業(yè)務(wù)取消,預(yù)留資源釋放。
在try階段,是對業(yè)務(wù)系統(tǒng)進行檢查及資源預(yù)覽,比如訂單和存儲操作,
需要檢查庫存剩余數(shù)量是否夠用,并進行預(yù)留,預(yù)留操作的話就是新建一個可用庫存數(shù)量字段,
Try階段操作是對這個可用庫存數(shù)量進行操作
#基于TCC實現(xiàn)的分布式事務(wù)框架
>> ByteTCC:https://github.com/liuyangming/ByteTCC
>> tcc-transaction:https://github.com/changmingxie/tcc-transaction

比如下一個訂單減一個庫存.png
#比如下一個訂單減一個庫存執(zhí)行流程:
1.Try階段:
訂單系統(tǒng)將當前訂單狀態(tài)設(shè)置為支付中,庫存系統(tǒng)校驗當前剩余庫存數(shù)量是否大于1,
然后將可用庫存數(shù)量設(shè)置為庫存剩余數(shù)量-1,
2.如果Try階段執(zhí)行成功,執(zhí)行Confirm 階段,將訂單狀態(tài)修改為支付成功,庫存剩余數(shù)量修改為可用庫存數(shù)量
3.如果Try階段執(zhí)行失敗,執(zhí)行Cancel 階段,將訂單狀態(tài)修改為支付失敗,可用庫存數(shù)量修改為庫存剩余數(shù)量
基于TCC實現(xiàn)分布式事務(wù),代碼邏輯相對復(fù)雜一些,
需要將原來的接口的邏輯拆分為:try,confirm ,cancel 三個接口的邏輯
參考資料
https://blog.csdn.net/sinat_38570489/article/details/91363054
https://mp.weixin.qq.com/s/ruHgaWYk-pe0nkXChtHclg
https://blog.csdn.net/Saintyyu/article/details/100822735 (X/Open DTP模型與XA協(xié)議)