2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

真是絕了,做了這么多年程序員第一次搞懂微服務(wù)架構(gòu)的數(shù)據(jù)一致性

 邸彥強(qiáng) 2022-06-16 發(fā)布于河北

微服務(wù)架構(gòu)的數(shù)據(jù)一致性

微服務(wù)架構(gòu)下,最好的分布式數(shù)據(jù)一致性解決方案就是盡量避免分布式事務(wù),然而,在很多場景下,分布式事務(wù)是難以避免的。在金融、電信領(lǐng)域中,很多業(yè)務(wù)場景要求數(shù)據(jù)的強(qiáng)一致性,同時(shí)要保證服務(wù)的可擴(kuò)展性和可靠性。如何保證分布式事務(wù)下的數(shù)據(jù)一致性成為微服務(wù)架構(gòu)的一個(gè)重要課題和難點(diǎn)。

解決方案概覽

在工程領(lǐng)域,分布式事務(wù)的討論主要聚焦于強(qiáng)一致性和最終一致性的解決方案。常見的分布式事務(wù)有基于XA協(xié)議的兩階段(2PC)提交模式,以及改良版本的三階段(3PC)提交模式。Java事務(wù)編程接口(Java Transaction API,JTA)和Java事務(wù)服務(wù)(Java TransactionService,JTS)正是基于XA協(xié)議的實(shí)現(xiàn)。分布式事務(wù)包括事務(wù)管理器TM(Transaction Manager)和一個(gè)或多個(gè)支持XA協(xié)議的資源管理器RM(Resource Manager)。在微服務(wù)架構(gòu)下,我們傾向使用最終一致性的方案。下面將介紹2PC模式、TCC模式、Saga模式等。

● 2PC模式,分布式事務(wù)比較典型的解決方案,但是對于微服務(wù)架構(gòu)而言,可能這一方案并不適用,主要原因是不同微服務(wù)可能使用的數(shù)據(jù)存儲類型不同。如果使用的NoSQL不支持事務(wù)的數(shù)據(jù)庫,那么事務(wù)根本無法實(shí)現(xiàn)2PC模式。此外,2PC模式本身也存在同步阻塞、單點(diǎn)故障和性能問題。

● TCC模式,相比2PC模式,具有更強(qiáng)的靈活性和性能優(yōu)勢,TCC模式本質(zhì)上是基于服務(wù)層的2PC編程模式,把事務(wù)從數(shù)據(jù)庫層的事務(wù)操作邏輯抽象到業(yè)務(wù)服務(wù)層,通過服務(wù)層業(yè)務(wù)邏輯實(shí)現(xiàn)服務(wù)的補(bǔ)償模式。

● Saga模式,核心理念是將事務(wù)切分成一組依次執(zhí)行的短事務(wù),也可以理解成基于業(yè)務(wù)補(bǔ)償邏輯實(shí)現(xiàn)分布式下的高性能分布式事務(wù)模式。較之基于單一數(shù)據(jù)庫資源訪問的本地事務(wù),分布式事務(wù)的應(yīng)用架構(gòu)更為復(fù)雜。在不同的分布式應(yīng)用架構(gòu)下,實(shí)現(xiàn)一個(gè)分布式事務(wù)要考慮的問題并不完全一樣,比如對多資源的協(xié)調(diào)、事務(wù)的跨服務(wù)傳播、業(yè)務(wù)的侵入性、隔離性等,實(shí)現(xiàn)機(jī)制也是復(fù)雜多變的。

● 可靠消息模式的解決方案是使用消息隊(duì)列進(jìn)行系統(tǒng)間的解耦。

由上游服務(wù)發(fā)起事件,通過消息隊(duì)列傳遞到下游服務(wù),下游服務(wù)接收到消息后進(jìn)行事件消費(fèi),最終完成業(yè)務(wù),達(dá)到數(shù)據(jù)一致。為了解決消息隊(duì)列及上下游服務(wù)的不可靠性,通常還會借助額外的事件表和定時(shí)器輔助完成數(shù)據(jù)補(bǔ)償。

兩階段提交模式

2PC(兩階段提交)

2PC是一個(gè)非常經(jīng)典的強(qiáng)一致、中心化的通過原子提交來實(shí)現(xiàn)分布式事務(wù)一致性管理的協(xié)議。這里所說的中心化指協(xié)議中有兩類節(jié)點(diǎn):

中 心 化 協(xié) 調(diào) 者 節(jié) 點(diǎn) ( Coordinator ) 和 N 個(gè) 參 與 者 節(jié) 點(diǎn)(Participant)。當(dāng)一個(gè)事務(wù)跨越多個(gè)節(jié)點(diǎn)時(shí),為了保持事務(wù)的ACID特性,需要協(xié)調(diào)者統(tǒng)一掌控所有節(jié)點(diǎn)(又稱作參與者)的操作結(jié)果,并最終指示這些節(jié)點(diǎn)是否要把操作結(jié)果進(jìn)行真正的提交或回滾。

2PC將整個(gè)事務(wù)流程分為兩個(gè)階段:準(zhǔn)備階段(Prepare Phase)和提交階段(Commit Phase)。整個(gè)事務(wù)過程由事務(wù)管理器和參與者組成,事務(wù)管理器負(fù)責(zé)決策整個(gè)分布式事務(wù)的提交和回滾,事務(wù)參與者負(fù)責(zé)自己本地事務(wù)的提交和回滾。大部分關(guān)系數(shù)據(jù)庫,如Oracle、MySQL,都支持兩階段提交協(xié)議。下面是計(jì)算機(jī)數(shù)據(jù)庫進(jìn)行兩階段提交的說明。

● 準(zhǔn)備階段:事務(wù)管理器為每個(gè)參與者準(zhǔn)備(Prepare)消息,每個(gè)參與者在本地執(zhí)行事務(wù),并寫本地的Undo/Redo日志,此時(shí)事務(wù)沒有被提交。(Undo日志記錄修改的數(shù)據(jù),用于數(shù)據(jù)回滾;Redo日志記錄修改后的數(shù)據(jù),用于提交事務(wù)后寫入數(shù)據(jù)文件)。

● 提交階段:如果事務(wù)管理器收到了參與者執(zhí)行失敗或者超時(shí)的消息,則直接向每個(gè)參與者發(fā)送回滾消息;否則,發(fā)送提交消息。參與者根據(jù)事務(wù)管理器的消息執(zhí)行提交或者回滾操作,并釋放事務(wù)處理過程中使用的鎖資源。

2PC的算法思路可以概括為:參與者將操作成敗的結(jié)果通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是執(zhí)行提交操作還是回滾操作。兩階段提交就是分成兩個(gè)階段提交,第一階段詢問各個(gè)事務(wù)數(shù)據(jù)源是否準(zhǔn)備好,第二階段才真正將數(shù)據(jù)提交給事務(wù)數(shù)據(jù)源。但因?yàn)?PC協(xié)議成本比較高,又有全局鎖的問題,性能會比較差?,F(xiàn)在我們基本上不會采用這種強(qiáng)一致性解決方案。2PC流程如下圖所示。

文章圖片1

在2PC中,如果兩階段出現(xiàn)協(xié)調(diào)者和參與者都宕機(jī)的情況,則有可能出現(xiàn)數(shù)據(jù)不一致的問題,同時(shí)還存在著諸如同步阻塞、單點(diǎn)問題、腦裂等問題,所以研究者們在2PC的基礎(chǔ)上做了改進(jìn),提出了3PC。

3PC(三階段提交)

3PC是2PC的改進(jìn)版本,流程如下圖所示。

文章圖片2

3PC要解決的最關(guān)鍵問題就是協(xié)調(diào)者和參與者同時(shí)宕機(jī)的問題,所以3PC將2PC的第一階段一分為二,形成了由canCommit、preCommit和Commit 3個(gè)階段組成的事務(wù)處理協(xié)議。

3PC的核心理念是:在詢問時(shí)并不鎖定資源,除非所有參與者都同意了,才開始鎖資源。一旦參與者無法及時(shí)收到來自協(xié)調(diào)者的信息,它就會默認(rèn)執(zhí)行Commit,而不會一直持有事務(wù)資源并處于阻塞狀態(tài),但是這種機(jī)制也會導(dǎo)致數(shù)據(jù)一致性問題。3PC在2PC的基礎(chǔ)上做了如下改進(jìn):

● 增加了超時(shí)機(jī)制。

● 在兩階段之間插入了準(zhǔn)備階段。

TCC補(bǔ)償模式

關(guān)于TCC(Try-Confirm-Cancel)的概念,最早是由Pat Helland在2007年發(fā)表的一篇名為Lifebeyond Distributed Transactions:anApostate’s Opinion的論文中提出的。在該論文中,TCC還是以
Tentative-Confirmation-Cancellation命名的。

TCC的核心思想是:針對每個(gè)操作都要注冊一個(gè)與其對應(yīng)的確認(rèn)和補(bǔ)償(撤銷)操作。TCC事務(wù)處理流程和2PC類似,不過2PC通常都在跨庫的DB層面,而TCC本質(zhì)上就是一個(gè)應(yīng)用層面的2PC,需要通過業(yè)務(wù)邏輯來實(shí)現(xiàn)。

TCC模式的工作原理

TCC模式的工作原理如下圖所示。TCC將一個(gè)完整的事務(wù)提交分為Try、Confirm、Cancel 3個(gè)操作。

文章圖片3

● Try:預(yù)留業(yè)務(wù)資源/數(shù)據(jù)效驗(yàn)。

● Confirm:確認(rèn)執(zhí)行真正要執(zhí)行的業(yè)務(wù),如果所有事務(wù)參與者的Try操作都執(zhí)行成功了,就會調(diào)用所有事務(wù)參與者的Confirm操作,確認(rèn)資源。Confirm操作滿足冪等性,要求具備冪等設(shè)計(jì),Confirm失敗后需要進(jìn)行重試。

● Cancel:取消執(zhí)行,如果有事務(wù)參與者在Try階段執(zhí)行失敗,就調(diào)用所有已成功執(zhí)行Try階段的參與者的Cancel方法,釋放Try階段占用的資源。Cancel操作滿足冪等性,Cancel階段的異常和Confirm階段的異常處理方案基本上一致。

下面是實(shí)際模擬用戶下單的一個(gè)業(yè)務(wù)場景使用TCC模式的主要流程圖。TCC第一階段是圖中的粗線條部分,這個(gè)階段需要分別執(zhí)行訂單服務(wù)和庫存服務(wù)的Try事務(wù),預(yù)留必需的業(yè)務(wù)資源;在第一階段執(zhí)行成功后,就會進(jìn)入第二階段的Confirm操作,如果不成功,則進(jìn)行Cancel操作。

文章圖片4

TCC的優(yōu)點(diǎn)和缺點(diǎn)

● TCC的優(yōu)點(diǎn):讓應(yīng)用自己定義數(shù)據(jù)庫操作的粒度,使降低鎖沖突、提高吞吐量成為可能。TCC的特點(diǎn)在于業(yè)務(wù)資源檢查與加鎖,一階段進(jìn)行校驗(yàn),鎖定資源,如果第一階段都成功,則第二階段對鎖定資源進(jìn)行交易邏輯,否則對鎖定資源進(jìn)行釋放,這樣就避免了數(shù)據(jù)庫兩階段提交中的鎖沖突和長事務(wù)低性能風(fēng)險(xiǎn)。

● TCC的缺點(diǎn):業(yè)務(wù)邏輯的每個(gè)分支都需要實(shí)現(xiàn)Try、Confirm、Cancel 3個(gè)操作,應(yīng)用侵入性較強(qiáng),改造成本高。另外,實(shí)現(xiàn)難度較大,需要按照網(wǎng)絡(luò)狀態(tài)、系統(tǒng)故障等不同的失敗原因?qū)崿F(xiàn)不同的回滾策略。為了滿足一致性的要求,Confirm和Cancel接口必須實(shí)現(xiàn)冪等。

TCC的開源解決方案

目前,國內(nèi)的螞蟻金服主要采用TCC模式進(jìn)行分布式事務(wù)管理。下面總結(jié)了常用的TCC開源分布式管理框架:

● Seata

● Tcc-transaction

● Hmily

● ByteTCC

● EasyTransaction

Saga長事務(wù)模式

1987年,普林斯頓大學(xué)的Hector Garcia-Molina和Kenneth Salem發(fā)表了一篇論文:Sagas[3]。這篇論文提出了使用Saga機(jī)制作為分布式事 務(wù) 的 替 代 品 , 以 解 決 長 時(shí) 間 運(yùn) 行 的 分 布 式 事 務(wù) ( long-LivedTransaction,LLT)問題,LLT指長時(shí)間持有數(shù)據(jù)庫資源的長活事務(wù)。

該論文認(rèn)為業(yè)務(wù)過程經(jīng)常由很多步驟組成,每一個(gè)步驟都涉及一個(gè)事務(wù),如果將這些事務(wù)組成一個(gè)分布式事務(wù),就可以實(shí)現(xiàn)總體一致。然而在長時(shí)間運(yùn)行的分布式事務(wù)中,使用分布式事務(wù)會影響效率和系統(tǒng)的并發(fā)處理能力,因?yàn)樵趫?zhí)行分布式事務(wù)時(shí)會有鎖產(chǎn)生。Saga通過確保每一個(gè)業(yè)務(wù)過程都有修正事務(wù)來減少系統(tǒng)對分布式事務(wù)的依賴。這種在業(yè)務(wù)流程中執(zhí)行修正事務(wù)的方式最終保證了系統(tǒng)數(shù)據(jù)一致性。

每一個(gè)LLT的Saga都由一系列sub-transaction Ti組成,每個(gè)Ti都有對應(yīng)的補(bǔ)償動作Ci,補(bǔ)償動作用于撤銷Ti造成的結(jié)果。同時(shí)Saga定義了兩種恢復(fù)策略:

● 向后恢復(fù)模式(Backward Recovery),在這種模式下,每一個(gè)內(nèi)部子事務(wù)都有一個(gè)對應(yīng)的補(bǔ)償事務(wù),如果任一子事務(wù)失敗,則將撤銷之前所有成功的sub-transaction,使整個(gè)Saga的執(zhí)行結(jié)果都撤銷。

● 向前恢復(fù)模式(Forward Recovery),這種模式假設(shè)每個(gè)子事務(wù)最終都會成功,適用于必須要成功的場景,執(zhí)行順序如下:T1,T2,…,Tj(失?。琓j(重試),…,Tn,其中Tj是發(fā)生錯(cuò)誤的sub-transaction,此時(shí)執(zhí)行重試邏輯,在該模式下不需要執(zhí)行補(bǔ)償事務(wù)。

微服務(wù)架構(gòu)大師Chris Richardson在介紹微服務(wù)架構(gòu)與數(shù)據(jù)一致性技術(shù)時(shí),提出了Saga模式,將微服務(wù)中的分布式事務(wù)劃分為一組小的事務(wù),所劃分事務(wù)或者全部提交,或者全部回滾。強(qiáng)調(diào)在微服務(wù)中,每個(gè)單獨(dú)的微服務(wù)都可以確保ACID,因?yàn)槊恳粋€(gè)微服務(wù)都具備自己的數(shù)據(jù)庫,但是,Saga模式作為整體并不保證隔離性,所以需要對異常情況進(jìn)行補(bǔ)償操作。

在Saga模式中,為了保障事務(wù)提交和回滾,應(yīng)使用事務(wù)日志結(jié)尾和消息傳遞的方式。在發(fā)消息之前,將消息寫入本地?cái)?shù)據(jù)庫,這就是所謂的事務(wù)日志結(jié)尾。它的作用是當(dāng)新的日志到來時(shí),可以直接發(fā)布,這樣就可以強(qiáng)化ACD特性;同時(shí)Saga模式中子模塊之間的消息通信建議采用消息傳遞方式,因?yàn)楹虷TTP通信協(xié)議相比,消息傳遞方式具備持久性。

Saga模式的工作原理

在微服務(wù)架構(gòu)下,Saga存在兩種協(xié)調(diào)模式。

● 編排模式(Choreography)

這種模式在微服務(wù)之間傳遞Saga,沒有重協(xié)調(diào)器,每個(gè)微服務(wù)都監(jiān)聽其他服務(wù),并決定采取行動。這種模式最大的優(yōu)勢就是簡單,容易理解,參與者之間松散耦合,對于參與者較少的情況,適合采用這種模式。下面是使用編排模式的分布式事務(wù)時(shí)序圖,實(shí)線表示消息發(fā)布,虛線表示訂閱。

文章圖片5

事件執(zhí)行順序如下:

(1)訂單服務(wù)(Order Service)在Approval_pending狀態(tài)下創(chuàng)建了訂單,并發(fā)布訂單創(chuàng)建事件。

(2)庫存服務(wù)(Inventory Service)消費(fèi)訂單創(chuàng)建事件,在Inventory_pending狀態(tài)下驗(yàn)證訂單,訂單出庫,并創(chuàng)建InventoryCreate Event。

(3)賬戶服務(wù)(Account Service)消費(fèi)訂單創(chuàng)建事件并進(jìn)入等待的狀態(tài)。

(4)賬戶服務(wù)消費(fèi)Inventory Event,收取費(fèi)用并發(fā)布AccountEvent。

( 5 ) 庫 存 服 務(wù) 訂 閱 Account Event 商 品 出 庫 , 更 改Inventory_pending狀態(tài)為Accept狀態(tài)。

(6)訂單服務(wù)收到Account Event,訂單狀態(tài)改為Approved狀態(tài)。

(7)如果上述訂單服務(wù)失敗,那么庫存服務(wù)消費(fèi)費(fèi)用收取失敗事件,回滾之前庫存事務(wù)清單,將狀態(tài)改為拒絕。

(8)如果上述賬戶服務(wù)失敗,那么訂單服務(wù)消費(fèi)費(fèi)用收取失敗事件,回滾訂單狀態(tài)改為拒絕。

● 編制模式(Orchestrator)

這種模式需要一個(gè)集中的服務(wù)觸發(fā)器,跟蹤Saga的所有子任務(wù)調(diào)用情況,根據(jù)調(diào)用情況來決定是否采用補(bǔ)償措施。這種中央?yún)f(xié)調(diào)的方式可以減少每一個(gè)微服務(wù)之間的循環(huán)依賴,集成處理事件決策和邏輯排序,也更容易推理Saga組合,保證長事務(wù)數(shù)據(jù)的最終一致性。使用業(yè)務(wù)流程時(shí),可以定義一個(gè)控制類,其唯一職責(zé)是告訴Saga參與者該做什么。Saga控制使用命令或異步回復(fù)樣式交互與參與者進(jìn)行通信。

下面是使用編制模式的分布式事務(wù)時(shí)序圖,實(shí)線表示消息request,虛線表示消息reply。

文章圖片6

事件執(zhí)行順序如下:

(1)訂單服務(wù)(Order Service)創(chuàng)建一個(gè)訂單和一個(gè)訂單控制器:Saga Orchestrator。

(2)Saga Orchestrator向庫存服務(wù)(Inventory Service)發(fā)送一個(gè)創(chuàng)建訂單命令。

(3)庫存服務(wù)回復(fù)庫存出庫命令。

(4)Saga Orchestrator向賬號服務(wù)(Account Service)發(fā)送一個(gè)費(fèi)用收取命令。

(5)賬號服務(wù)回復(fù)訂單費(fèi)用扣除命令。

(6)Saga Orchestrator向訂單服務(wù)發(fā)送一個(gè)訂單已批準(zhǔn)命令。

說明:基于業(yè)務(wù)流程,Saga編制的每個(gè)步驟都包括更新數(shù)據(jù)庫和發(fā)布消息的服務(wù),例如訂單服務(wù)持久化和創(chuàng)建Saga Orchestrator,并向第一個(gè)Saga參與者發(fā)送消息。第一個(gè)Saga參與者是庫存服務(wù),通過更新數(shù)據(jù)庫回復(fù)消息。然后訂單服務(wù)通過更新Saga協(xié)調(diào)器的狀態(tài)向下一個(gè)Saga參與者發(fā)送命令,并處理參與者的命令回復(fù)響應(yīng),服務(wù)必須使用事務(wù)性的消息傳遞,以便自動更新數(shù)據(jù)并發(fā)布消息。

編排模式與編制模式

微服務(wù)中推薦使用編制模式。相比編排模式,編制模式有下面幾個(gè)優(yōu)勢。

● 編制模式有更簡化的依賴關(guān)系。編排模式中,服務(wù)之間需要掌握相互依賴關(guān)系,而且針對不同的異常,可能還需要采用不同的補(bǔ)償措施,Saga Orchestrator則調(diào)用Saga參與者,所有參與者之間是不需要了解Orchestrator的實(shí)現(xiàn)細(xì)節(jié)的。

● 每個(gè)服務(wù)只需要暴露各自的API供Orchestrator調(diào)用即可,因此每個(gè)微服務(wù)之間有較少耦合,可以降低每個(gè)參與者的復(fù)雜度。

● 可以使用Saga Orchestrator更加方便地增加或減少Saga分布式事務(wù)邏輯,不需要改變每一個(gè)參與者的Saga內(nèi)部事務(wù)。同時(shí)可以基于Orchestrator進(jìn)行關(guān)注點(diǎn)分離,并簡化業(yè)務(wù),操作更加容易、方便。

Saga與ACID

Saga不提供對整體隔離性的保證。一個(gè)長事務(wù)劃分為若干本地事務(wù),在本地事務(wù)提交后,整個(gè)Saga未完成之前,其他服務(wù)可以訪問“未完成”的中間狀態(tài)事務(wù)數(shù)據(jù);Saga協(xié)調(diào)器實(shí)現(xiàn)原子特性,通過日志實(shí)現(xiàn)持久性;通過本地日志與Saga日志保證事務(wù)一致性。所以Saga模式只支持ACD,不提供隔離性的保證。

Saga與2PC的區(qū)別

Saga與2PC最主要的區(qū)別在于,2PC是一個(gè)強(qiáng)一致性的分布式事務(wù)模式,Saga和TCC都通過應(yīng)用服務(wù)層犧牲ACID特性來實(shí)現(xiàn)事務(wù)的最終一致性,Saga和TCC可以理解為分布式環(huán)境下通過事務(wù)補(bǔ)償模式的事務(wù)控制模型,只是Saga和TCC有各自不同的實(shí)現(xiàn)策略。

Saga與TCC的區(qū)別

Saga和TCC最大的區(qū)別在于,Saga沒有預(yù)留資源,而是直接提交到數(shù)據(jù)庫,Saga比TCC少了一步Try操作,無論最終事務(wù)成功或失敗,TCC都需要與事務(wù)參與方交互兩次。而Saga在事務(wù)成功的情況下只需要與事務(wù)參與方交互一次。如果事務(wù)失敗,則需要采取補(bǔ)償事務(wù)的方式進(jìn)行回滾。

Saga的開源解決方案

Saga為相互獨(dú)立、自治的微服務(wù)提供了一種分布式網(wǎng)絡(luò)場景下的數(shù)據(jù)一致性的解決方案。下面是一些Saga模式的開源解決方案,由于篇幅所限,這里不再贅述方案的實(shí)現(xiàn)細(xì)節(jié)。

● ServiceComb Saga

● Axon Framework

● Eventuate-tram-sagas

可靠消息模式

可靠消息模式主要采用一個(gè)可靠的消息中間件作為中介,事務(wù)的發(fā)起方在完成本地事務(wù)后向可靠的消息中間件發(fā)起消息,事務(wù)消費(fèi)方在收到消息后處理消息,該方案強(qiáng)調(diào)的是雙方最終的數(shù)據(jù)一致性。

如下圖所示,訂單服務(wù)將消息發(fā)送給訂單服務(wù)隊(duì)列,庫存服務(wù)監(jiān)聽訂閱了訂單服務(wù)的消息隊(duì)列,并從消息隊(duì)列中消費(fèi)信息。由此可以看到,從事務(wù)的發(fā)起方到消息中間件,再到事務(wù)的消費(fèi)方,中間都會通過網(wǎng)絡(luò),由于網(wǎng)絡(luò)的不可靠性,導(dǎo)致分布式事務(wù)的數(shù)據(jù)不一致性。

文章圖片7

基于這種網(wǎng)絡(luò)的不可靠性,依靠本地消息表和可靠消息隊(duì)列的模式可以解決分布式事務(wù)的不一致性。而這種模式,對業(yè)務(wù)的侵入性相對較小,在實(shí)現(xiàn)復(fù)雜度上也比較可控,國內(nèi)很多互聯(lián)網(wǎng)公司都采用了可靠消息模式來解決分布式事務(wù)的一致性問題。而這一方案的提出和思路來源于Ebay,之后這種模式在業(yè)內(nèi)被廣泛使用。這種分布式事務(wù)模式的本質(zhì)是本地事務(wù)+可靠消息,以達(dá)到最終事務(wù)的一致性。我們來看可靠消息模式的具體實(shí)現(xiàn)原理,如下圖所示。

文章圖片8

可靠消息模式的思想是:事務(wù)的發(fā)起方需要額外創(chuàng)建一個(gè)本地消息表,將本地消息表和業(yè)務(wù)數(shù)據(jù)放在同一個(gè)事務(wù)中提交執(zhí)行。也就是說,二者要么同時(shí)成功,要么同時(shí)失敗。例如,將訂單創(chuàng)建事務(wù)和庫存驗(yàn)證及庫存出庫事件消息日志放入同一個(gè)事務(wù)中,下面是偽代碼舉例:

文章圖片9
文章圖片10

從上述偽代碼可知,本地?cái)?shù)據(jù)庫與庫存出庫事務(wù)處于同一事務(wù)中,二者的綁定操作具備了原子性,工作時(shí)序如下:

(1)本地事務(wù)提交后,可以使用觸發(fā)的方式對本地消息表進(jìn)行查詢和消息推送,或者使用定時(shí)器的方式輪詢本地消息表進(jìn)行消息推送。

(2)消費(fèi)者的消息可以使用可靠的消息中間件機(jī)制,例如RabbitMQ中的ACK(消息確認(rèn)機(jī)制)保證消費(fèi)者可以一定消費(fèi)到消息;

又如庫存服務(wù)在接收到消息并且完成消息業(yè)務(wù)處理后,回復(fù)ACK,說明此時(shí)庫存服務(wù)已經(jīng)正確同步數(shù)據(jù);如果庫存服務(wù)沒有回復(fù)ACK,則消息中間件在沒收到ACK消息時(shí),將保留消息,并重復(fù)投遞此消息。

(3)當(dāng)消息中間件反饋消費(fèi)成功后,庫存服務(wù)可以回調(diào)一個(gè)訂單服務(wù)的確認(rèn)API,這時(shí)訂單服務(wù)可以從本地事務(wù)表中刪除對應(yīng)的消息隊(duì)列。

(4)在訂單服務(wù)中,如果定時(shí)任務(wù)重復(fù)把本地事務(wù)表中的消息發(fā)到庫存服務(wù),則需要消息消費(fèi)方(庫存服務(wù))提供消息的冪等性支持。

冪等性

簡單來說,冪等性的概念就是:除了錯(cuò)誤或者過期的請求(換言之就是成功的請求),無論多次調(diào)用還是單次調(diào)用,最終得到的效果都是一致的。通俗來說,只要有一次調(diào)用成功,再采用相同的請求參數(shù),無論調(diào)用多少次(重復(fù)提交),都應(yīng)該返回成功。

例如庫存服務(wù)對外提供服務(wù)接口,必須承諾實(shí)現(xiàn)接口的冪等性,這一點(diǎn)在分布式系統(tǒng)中極其重要。

● 對于HTTP調(diào)用,承諾冪等性可以避免表單或者請求操作重復(fù)提交,造成業(yè)務(wù)數(shù)據(jù)重復(fù)。

● 對于異步消息調(diào)用,承諾冪等性通過對消息去重處理也是為了避免重復(fù)消費(fèi)造成業(yè)務(wù)數(shù)據(jù)重復(fù)。

下面是幾種常用的冪等性處理設(shè)計(jì)方案。

● 數(shù)據(jù)庫表設(shè)計(jì)對邏輯上唯一的業(yè)務(wù)鍵唯一索引,這是在數(shù)據(jù)庫層面做最后的保障。

● 業(yè)務(wù)邏輯上的防重,例如創(chuàng)建訂單的接口,首先通過訂單號查詢庫表中是否已經(jīng)存在對應(yīng)的訂單,如果存在,則不做處理,直接返回成功。

補(bǔ)償方案

在可靠消息事務(wù)方案中,事務(wù)發(fā)起方需要確保消息發(fā)送到消息隊(duì)列中,而消息隊(duì)列成為系統(tǒng)的瓶頸。當(dāng)消息隊(duì)列異常,或者消息消費(fèi)失敗導(dǎo)致數(shù)據(jù)不一致時(shí),需要采取補(bǔ)償措施,而常用的補(bǔ)償方案由消息消費(fèi)方負(fù)責(zé)。之所以使用消費(fèi)方補(bǔ)償模式有下面兩個(gè)主要理由:

● 一般來說,數(shù)據(jù)不一致大概率發(fā)生在消息消費(fèi)異常場景,如果由消息發(fā)送方補(bǔ)償錯(cuò)誤,往往無法解決消費(fèi)異常問題;同時(shí)一個(gè)消息可能存在多個(gè)消費(fèi)方,如果消息補(bǔ)償模塊在所有上游服務(wù)中編寫,可能無法滿足所有消費(fèi)方的異常補(bǔ)償場景。

● 當(dāng)消費(fèi)方出現(xiàn)問題時(shí),需要定位事務(wù)發(fā)起方,然后才能通過上游來補(bǔ)償,這種方式會增加處理生產(chǎn)問題的復(fù)雜度。

異步消息交互時(shí),采取的補(bǔ)償措施通常統(tǒng)一由消息消費(fèi)方實(shí)現(xiàn),這種方式將類似本地事件表的方式,在消息消費(fèi)失敗后,將失敗消息寫入本地?cái)?shù)據(jù)庫,然后啟動定時(shí)任務(wù)進(jìn)行重試,當(dāng)達(dá)到重試上限時(shí),進(jìn)行預(yù)警和人工干預(yù)。

RabbitMQ可靠消息傳輸實(shí)踐

在眾多消息隊(duì)列中,RabbitMQ最重要的特性就是將消息的可靠性作為傳輸消息考慮的第一要素。目前,RabbitMQ已經(jīng)成為金融行業(yè)中消息隊(duì)列的標(biāo)配。我們將通過RabbitMQ的幾個(gè)關(guān)鍵因素講解RabbitMQ如何保證消息的可靠傳輸。RabbitMQ流程如下圖所示。

文章圖片11

確認(rèn)機(jī)制

網(wǎng)絡(luò)異常、機(jī)器異常、程序異常等多種情況都可能導(dǎo)致業(yè)務(wù)丟失消息。對消息進(jìn)行確認(rèn)可以解決消息的丟失問題,確認(rèn)成功意味著消息已被驗(yàn)證并被正確處理。確認(rèn)機(jī)制能用在兩個(gè)方向:允許消費(fèi)者告訴服務(wù)器(Broker)已經(jīng)收到了消息,也允許服務(wù)器告訴生產(chǎn)者接收到了消息。前者就是我們常說的消費(fèi)者ACK,后者就是我們常說的生產(chǎn)者Confirm。

RabbitMQ使用生產(chǎn)者消息確認(rèn)、消費(fèi)者消息確認(rèn)機(jī)制來提供可靠交付功能。

● 生產(chǎn)者消息確認(rèn):生產(chǎn)者向RabbitMQ發(fā)送消息后,等待它回復(fù)確認(rèn)成功;否則生產(chǎn)者向RabbitMQ重發(fā)該消息。此過程可以異步進(jìn)行,生產(chǎn)者持續(xù)發(fā)送消息,RabbitMQ將消息批量處理后再回復(fù)確認(rèn);生產(chǎn)者通過識別確認(rèn)返回中的ID來確定哪些消息被成功處理。開啟生產(chǎn)者消息確認(rèn)機(jī)制:

文章圖片12

● 消費(fèi)者消息確認(rèn):RabbitMQ向消費(fèi)者投遞消息后,等待消費(fèi)者回復(fù)確認(rèn)成功;否則RabbitMQ重新向消費(fèi)者投遞該消息。該過程同樣可以異步處理,RabbitMQ持續(xù)投遞消息,消費(fèi)者批量處理完后回復(fù)確認(rèn)??梢钥闯?,RabbitMQ/AMQP提供的是“至少一次交付”(at-least-once delivery)的策略,異常情況下消息會被重復(fù)投遞或消費(fèi)。開啟消費(fèi)者消息確認(rèn)機(jī)制:

文章圖片13

持久化機(jī)制

設(shè)置交換機(jī)、隊(duì)列和消息都為持久化,它可以在服務(wù)器重啟時(shí)保證消息不丟失信息,集群節(jié)點(diǎn)提供冗余能力,對解決Broker的單點(diǎn)故障至關(guān)重要。在RabbitMQ集群中,所有的定義都可以被冗余處理,例如交換器和綁定關(guān)系等,而隊(duì)列只存在于一個(gè)節(jié)點(diǎn)上。對于隊(duì)列而言,可以通過配置把隊(duì)列鏡像到多個(gè)節(jié)點(diǎn)上。

● 交換機(jī)的持久化(通過查看源碼易知,默認(rèn)是支持持久化的),代碼如下:

文章圖片14

● 隊(duì)列的持久化(通過查看源碼易知,默認(rèn)是支持持久化的),代碼如下:

文章圖片15

● 消 息 的 持 久 化 。 當(dāng) 我 們 使 用 RabbitTemplate 調(diào) 用convertAndSend(String exchange,String routingKey,final Object object)方法時(shí),默認(rèn)是持久化模式。

生產(chǎn)者

當(dāng)使用確認(rèn)機(jī)制時(shí),生產(chǎn)者從連接或者Channel故障中恢復(fù)過來,會重發(fā)沒有被Broker確認(rèn)簽收的消息。如此一來,消息就可能被重復(fù)發(fā)送,可能是由于網(wǎng)絡(luò)故障等原因,Broker發(fā)送了確認(rèn),但是生產(chǎn)者沒有收到而已?;蛘呦⒏揪蜎]有發(fā)送到Broker。正因?yàn)樯a(chǎn)者為了可靠性可能會重發(fā)消息,所以在消費(fèi)者消費(fèi)消息處理業(yè)務(wù)時(shí),還需要去重,或者對接收的消息做冪等處理(推薦冪等處理)。生產(chǎn)者增加確認(rèn)機(jī)制非常簡單,Channel開啟Confirm模式,然后增加監(jiān)聽即可。

文章圖片16

說 明 : RabbitMQ 還 有 事 務(wù) 機(jī) 制 ( txSelect 、 txCommit 、txRollback),也能保障消息的發(fā)送。不過事務(wù)機(jī)制是“同步阻塞”的,所以不推薦使用。而Confirm模式是“異步”機(jī)制。通過事務(wù)機(jī)制與Confirm模式的TPS性能對比,我們可以很明顯地看到,事務(wù)機(jī)制是性能最差的。

RabbitMQ支持的4種交換器類型中,只有fanout模式不存在路由不到隊(duì)列的情況。因?yàn)樗鼤詣勇酚傻剿嘘?duì)列中,跟綁定Key沒有任何關(guān)系。所以,在滿足業(yè)務(wù)的前提下,筆者建議,盡可能使用fanout模式的類型交換器。

DLX(Dead Letter Exchange,死信郵箱或死信交換機(jī))就是一個(gè)普通的交換機(jī),與一般的交換機(jī)沒有任何區(qū)別。當(dāng)消息在一個(gè)隊(duì)列中變成死信時(shí),通過這個(gè)交換機(jī)將死信發(fā)送到死信隊(duì)列中。

我們可以通過DLX來解決這個(gè)問題,假設(shè)一些消息沒有被消費(fèi),那么它就會被轉(zhuǎn)移到綁定的DLX上。對于這類消息,我們消費(fèi)并處理死信隊(duì)列即可。

文章圖片17
文章圖片18

消費(fèi)者

只有消費(fèi)者確認(rèn)的消息,RabbitMQ才會刪除它,不確認(rèn)就不會被刪除。所以,在消費(fèi)端,建議關(guān)閉自動確認(rèn)機(jī)制。應(yīng)該在收到消息、處理完業(yè)務(wù)后,手動確認(rèn)消息。消費(fèi)者手動確認(rèn)消息的實(shí)現(xiàn)代碼如下:

文章圖片19

注意上面方法中void basicAck(long deliveryTag,booleanmultiple)的第二個(gè)參數(shù)multiple。要說明這個(gè)參數(shù)的含義,首先需要清楚“deliveryTag”概念,即投遞消息的唯一標(biāo)識符,它是一個(gè)“單調(diào)遞增”的Long型正整數(shù)。假設(shè)此次basicAck的tag為123456,如果 multiple=false , 則 表 示 只 確 認(rèn) 簽 收 這 一 條 消 息 。 如 果multiple=true,則表示確認(rèn)簽收tag小于或等于123456的所有消息。

小結(jié)

在微服務(wù)架構(gòu)下,我們強(qiáng)調(diào)要根據(jù)微服務(wù)的數(shù)據(jù)類型和業(yè)務(wù)場景選擇合適的后端數(shù)據(jù)存儲類型。對于微服務(wù)架構(gòu)下分布式應(yīng)用中的數(shù)據(jù)一致性管理,不推薦使用分布式事務(wù),微服務(wù)數(shù)據(jù)架構(gòu)通過放棄分布式網(wǎng)絡(luò)的強(qiáng)一致性,來提升微服務(wù)之間的交互性能。另外,在微服務(wù)數(shù)據(jù)架構(gòu)中,我們介紹了常見的TCC、Saga、可靠消息模式,可以作為保證數(shù)據(jù)之間最終一致性的解決方案。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多