服務(wù)層拆分
服務(wù)層拆分也就是業(yè)務(wù)的服務(wù)化,系統(tǒng)架構(gòu)的演進是從集中式到分布式蚯妇,業(yè)務(wù)功能之間越來越解耦合局骤。
比如電商網(wǎng)站系統(tǒng)似袁,業(yè)務(wù)初期可能是一個單體工程支撐整套服務(wù),但隨著系統(tǒng)規(guī)模進一步變大许昨,參考康威定律珊搀,大多數(shù)公司都會將核心業(yè)務(wù)抽取出來蕊温,以作為獨立的服務(wù)扒磁。商品庆揪、訂單、庫存妨托、賬號信息都提供了各自領(lǐng)域的服務(wù)缸榛,業(yè)務(wù)邏輯的執(zhí)行散落在不同的服務(wù)器上。
用戶如果在某網(wǎng)站上進行一個下單操作兰伤,那么會同時依賴訂單服務(wù)内颗、庫存服務(wù)、支付扣款服務(wù)医清,這幾個操作如果有一個失敗起暮,那下單操作也就完不成,這就需要分布式事務(wù)來保證了会烙。
分布式事務(wù)解決方案
分布式事務(wù)的解決方案,典型的有兩階段和三階段提交協(xié)議筒捺、 TCC 分段提交柏腻,和基于消息隊列的最終一致性設(shè)計。
2PC 兩階段提交
兩階段提交(2PC系吭,Two-phase Commit Protocol)是非常經(jīng)典的強一致性五嫂、中心化的原子提交協(xié)議,在各種事務(wù)和一致性的解決方案中肯尺,都能看到兩階段提交的應(yīng)用沃缘。兩階段指的是commit-request階段和commit階段。
兩階段提交存在的問題:
1则吟、資源被同步阻塞
在執(zhí)行過程中槐臀,所有參與節(jié)點都是事務(wù)獨占狀態(tài),當(dāng)參與者占有公共資源時氓仲,那么第三方節(jié)點訪問公共資源會被阻塞水慨。
2、協(xié)調(diào)者可能出現(xiàn)單點故障
一旦協(xié)調(diào)者發(fā)生故障敬扛,參與者會一直阻塞下去晰洒。
3、在 Commit 階段出現(xiàn)數(shù)據(jù)不一致
在第二階段中啥箭,假設(shè)協(xié)調(diào)者發(fā)出了事務(wù) Commit 的通知谍珊,但是由于網(wǎng)絡(luò)問題該通知僅被一部分參與者所收到并執(zhí)行 Commit,其余的參與者沒有收到通知急侥,一直處于阻塞狀態(tài)砌滞,那么炼七,這段時間就產(chǎn)生了數(shù)據(jù)的不一致性。
3PC 三階段提交
三階段提交協(xié)議(3PC布持,Three-phase_commit_protocol)是在 2PC 之上擴展的提交協(xié)議豌拙,主要是為了解決兩階段提交協(xié)議的阻塞問題,從原來的兩個階段擴展為三個階段题暖,增加了超時機制按傅。
三階段中的 Three Phase 分別為 CanCommit、PreCommit胧卤、DoCommit 階段唯绍。
三階段提交協(xié)議存在的問題
三階段提交協(xié)議同樣存在問題,具體表現(xiàn)為枝誊,在階段三中况芒,如果參與者接收到了 PreCommit 消息后,出現(xiàn)了不能與協(xié)調(diào)者正常通信的問題叶撒,在這種情況下绝骚,參與者依然會進行事務(wù)的提交,這就出現(xiàn)了數(shù)據(jù)的不一致性祠够。
TCC 分段提交
TCC 是一個分布式事務(wù)的處理模型压汪,將事務(wù)過程拆分為 Try、Confirm古瓤、Cancel 三個步驟止剖,在保證強一致性的同時,最大限度提高系統(tǒng)的可伸縮性與可用性落君。
TCC 的具體流程如上圖所示:
Try 階段:調(diào)用 Try 接口穿香,嘗試執(zhí)行業(yè)務(wù),完成所有業(yè)務(wù)檢查绎速,預(yù)留業(yè)務(wù)資源皮获。
Confirm 或 Cancel 階段:兩者是互斥的,只能進入其中一個朝氓,并且都滿足冪等性魔市,允許失敗重試。
Confirm 操作:對業(yè)務(wù)系統(tǒng)做確認提交赵哲,確認執(zhí)行業(yè)務(wù)操作待德,不做其他業(yè)務(wù)檢查,只使用 Try 階段預(yù)留的業(yè)務(wù)資源枫夺。
Cancel 操作:在業(yè)務(wù)執(zhí)行錯誤将宪,需要回滾的狀態(tài)下執(zhí)行業(yè)務(wù)取消,釋放預(yù)留資源。
Try 階段失敗可以 Cancel较坛,如果 Confirm 和 Cancel 階段失敗了怎么辦印蔗?
TCC 中會添加事務(wù)日志,如果 Confirm 或者 Cancel 階段出錯丑勤,則會進行重試华嘹,所以這兩個階段需要支持冪等;如果重試失敗法竞,則需要人工介入進行恢復(fù)和處理等耙厚。
應(yīng)用 TCC 的優(yōu)缺點
實際開發(fā)中,TCC 的本質(zhì)是把數(shù)據(jù)庫的二階段提交上升到微服務(wù)來實現(xiàn)岔霸,從而避免數(shù)據(jù)庫二階段中長事務(wù)引起的低性能風(fēng)險薛躬。
所以說,TCC 解決了跨服務(wù)的業(yè)務(wù)操作原子性問題呆细,比如下訂單減庫存型宝,多渠道組合支付等場景,通過 TCC 對業(yè)務(wù)進行拆解絮爷,可以讓應(yīng)用自己定義數(shù)據(jù)庫操作的粒度趴酣,可以降低鎖沖突,提高系統(tǒng)的業(yè)務(wù)吞吐量略水。
TCC 的不足主要體現(xiàn)在對微服務(wù)的侵入性強价卤,TCC 需要對業(yè)務(wù)系統(tǒng)進行改造,業(yè)務(wù)邏輯的每個分支都需要實現(xiàn) try渊涝、Confirm、Cancel 三個操作床嫌,并且 Confirm跨释、Cancel 必須保證冪等。
另外 TCC 的事務(wù)管理器要記錄事務(wù)日志厌处,也會損耗一定的性能鳖谈。
從真實業(yè)務(wù)場景分析 TCC
下面以一個電商中的支付業(yè)務(wù)來演示,用戶在支付以后阔涉,需要進行更新訂單狀態(tài)缆娃、扣減賬戶余額、增加賬戶積分和扣減商品操作瑰排。
在實際業(yè)務(wù)中為了防止超賣贯要,有下單減庫存和付款減庫存的區(qū)別,支付除了賬戶余額椭住,還有各種第三方支付等崇渗,這里我們?yōu)榱嗣枋龇奖悖y(tǒng)一使用扣款減庫存,扣款來源是用戶賬戶余額宅广。
業(yè)務(wù)邏輯拆解
我們把訂單業(yè)務(wù)拆解為以下幾個步驟:
1葫掉、訂單更新為支付完成狀態(tài)
2、扣減用戶賬戶余額
3跟狱、增加用戶賬戶積分
4俭厚、扣減當(dāng)前商品的庫存
如果不使用事務(wù),上面的幾個步驟都可能出現(xiàn)失敗驶臊,最終會造成大量的數(shù)據(jù)不一致挪挤,比如訂單狀態(tài)更新失敗,扣款卻成功了资铡;或者扣款失敗电禀,庫存卻扣減了等情況,這個在業(yè)務(wù)上是不能接受的笤休,會出現(xiàn)大量的客訴尖飞。
如果直接應(yīng)用事務(wù),不使用分布式事務(wù)店雅,比如在代碼中添加 Spring 的聲明式事務(wù) @Transactional 注解政基,這樣做實際上是在事務(wù)中嵌套了遠程服務(wù)調(diào)用,一旦服務(wù)調(diào)用出現(xiàn)超時闹啦,事務(wù)無法提交沮明,就會導(dǎo)致數(shù)據(jù)庫連接被占用,出現(xiàn)大量的阻塞和失敗窍奋,會導(dǎo)致服務(wù)宕機荐健。另一方面,如果沒有定義額外的回滾操作琳袄,比如遇到異常江场,非 DB 的服務(wù)調(diào)用失敗時,則無法正確執(zhí)行回滾窖逗。
業(yè)務(wù)系統(tǒng)改造
下面應(yīng)用 TCC 事務(wù)址否,需要對業(yè)務(wù)代碼改造,抽象 Try碎紊、Confirm 和 Cancel 階段佑附。
Try 操作
Try 操作一般都是鎖定某個資源,設(shè)置一個預(yù)備的狀態(tài)仗考,凍結(jié)部分數(shù)據(jù)音同。比如,訂單服務(wù)添加一個預(yù)備狀態(tài)痴鳄,修改為 UPDATING瘟斜,也就是更新中的意思缸夹,凍結(jié)當(dāng)前訂單的操作,而不是直接修改為支付成功螺句。
庫存服務(wù)設(shè)置凍結(jié)庫存虽惭,可以擴展字段,也可以額外添加新的庫存凍結(jié)表蛇尚。積分服務(wù)和庫存一樣芽唇,添加一個預(yù)增加積分,比如本次訂單積分是 100取劫,添加一個額外的存儲表示等待增加的積分匆笤,賬戶余額服務(wù)等也是一樣的操作。
Confirm 操作
Confirm 操作就是把前邊的 Try 操作鎖定的資源提交谱邪,類比數(shù)據(jù)庫事務(wù)中的 Commit 操作炮捧。在支付的場景中,包括訂單狀態(tài)從準備中更新為支付成功惦银;庫存數(shù)據(jù)扣減凍結(jié)庫存咆课,積分數(shù)據(jù)增加預(yù)增加積分。
Cancel 操作
Cancel 操作執(zhí)行的是業(yè)務(wù)上的回滾處理扯俱,類比數(shù)據(jù)庫事務(wù)中的 Rollback 操作书蚪。首先訂單服務(wù),撤銷預(yù)備狀態(tài)迅栅,還原為待支付狀態(tài)或者已取消狀態(tài)殊校,庫存服務(wù)刪除凍結(jié)庫存,添加到可銷售庫存中读存,積分服務(wù)也是一樣为流,將預(yù)增加積分扣減掉。
執(zhí)行業(yè)務(wù)操作
下面來分析業(yè)務(wù)的實際執(zhí)行操作让簿,首先業(yè)務(wù)請求過來艺谆,開始執(zhí)行 Try 操作,如果 TCC 分布式事務(wù)框架感知到各個服務(wù)的 Try 階段都成功了以后拜英,就會執(zhí)行各個服務(wù)的 Confirm 邏輯。
如果 Try 階段有操作不能正確執(zhí)行琅催,比如訂單失效居凶、庫存不足等,就會執(zhí)行 Cancel 的邏輯藤抡,取消事務(wù)提交侠碧。
TCC 分布式服務(wù)組件
在業(yè)務(wù)中引入 TCC 一般是依賴單獨的 TCC 事務(wù)框架,可以選擇自研或者應(yīng)用開源組件缠黍。TCC 框架扮演了資源管理器的角色弄兜,常用的 TCC 開源組件有 Tcc-transaction、ByteTCC、Spring-cloud-rest-tcc 等替饿。
前面介紹過的 Seata语泽,可以選擇 TCC 事務(wù)模式,也支持了 AT 模式及 Saga 模式视卢。
以 Tcc-transaction 為例踱卵,源碼托管在 Github-tcc-transaction,提供了對 Spring 和 Dubbo 的適配据过,感興趣的話可以查看 tcc-transaction-tutorial-sample 學(xué)習(xí)惋砂。
基于消息補償?shù)淖罱K一致性
異步化在分布式系統(tǒng)設(shè)計中隨處可見,基于消息隊列的最終一致性就是一種異步事務(wù)機制绳锅,在業(yè)務(wù)中廣泛應(yīng)用西饵。
在具體實現(xiàn)上,基于消息補償?shù)囊恢滦灾饕斜镜叵⒈砗偷谌娇煽肯㈥犃械取?/p>
下面介紹一下本地消息表鳞芙,本地消息表的方案最初是由 ebay 的工程師提出眷柔,核心思想是將分布式事務(wù)拆分成本地事務(wù)進行處理,通過消息日志的方式來異步執(zhí)行积蜻。
本地消息表是一種業(yè)務(wù)耦合的設(shè)計闯割,消息生產(chǎn)方需要額外建一個事務(wù)消息表,并記錄消息發(fā)送狀態(tài)竿拆,消息消費方需要處理這個消息宙拉,并完成自己的業(yè)務(wù)邏輯,另外會有一個異步機制來定期掃描未完成的消息丙笋,確保最終一致性谢澈。
下面我們用下單減庫存業(yè)務(wù)來簡單模擬本地消息表的實現(xiàn)過程:
(1)系統(tǒng)收到下單請求,將訂單業(yè)務(wù)數(shù)據(jù)存入到訂單庫中御板,并且同時存儲該訂單對應(yīng)的消息數(shù)據(jù)锥忿,比如購買商品的 ID 和數(shù)量,消息數(shù)據(jù)與訂單庫為同一庫怠肋,更新訂單和存儲消息為一個本地事務(wù)敬鬓,要么都成功,要么都失敗笙各。
(2)庫存服務(wù)通過消息中間件收到庫存更新消息钉答,調(diào)用庫存服務(wù)進行業(yè)務(wù)操作,同時返回業(yè)務(wù)處理結(jié)果杈抢。
(3)消息生產(chǎn)方数尿,也就是訂單服務(wù)收到處理結(jié)果后,將本地消息表的數(shù)據(jù)刪除或者設(shè)置為已完成惶楼。
(4)設(shè)置異步任務(wù)右蹦,定時去掃描本地消息表诊杆,發(fā)現(xiàn)有未完成的任務(wù)則重試,保證最終一致性何陆。
以上就是基于本地消息表一致性的主流程晨汹,在具體實踐中,還有許多分支情況甲献,比如消息發(fā)送失敗宰缤、下游業(yè)務(wù)方處理失敗等,感興趣的同學(xué)可以思考下晃洒。
不要求最終一致性的柔性事務(wù)
除了上述幾種慨灭,還有一種不保證最終一致性的柔性事務(wù),也稱為盡最大努力通知球及,這種方式適合可以接受部分不一致的業(yè)務(wù)場景氧骤。
分布式事務(wù)有哪些開源組件
分布式事務(wù)開源組件應(yīng)用比較廣泛的是螞蟻金服開源的 Seata,也就是 Fescar吃引,前身是阿里中間件團隊發(fā)布的 TXC(Taobao Transaction Constructor)和升級后的 GTS(Global Transaction Service)筹陵。
Seata 的設(shè)計思想是把一個分布式事務(wù)拆分成一個包含了若干分支事務(wù)(Branch Transaction)的全局事務(wù)(Global Transaction)。分支事務(wù)本身就是一個滿足 ACID 的 本地事務(wù)镊尺,全局事務(wù)的職責(zé)是協(xié)調(diào)其下管轄的分支事務(wù)達成一致朦佩,要么一起成功提交,要么一起失敗回滾庐氮。
在 Seata 中语稠,全局事務(wù)對分支事務(wù)的協(xié)調(diào)基于兩階段提交協(xié)議,類似數(shù)據(jù)庫中的 XA 規(guī)范弄砍,XA 規(guī)范定義了三個組件來協(xié)調(diào)分布式事務(wù)仙畦,分別是 AP 應(yīng)用程序、TM 事務(wù)管理器音婶、RM 資源管理器慨畸、CRM 通信資源管理器。