日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一致 先验分布 后验分布_分布式事务常见解决方案与最终一致性

發(fā)布時(shí)間:2024/1/23 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一致 先验分布 后验分布_分布式事务常见解决方案与最终一致性 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
小編推薦:互聯(lián)網(wǎng)大背景下,微服務(wù)盛行,平時(shí)開發(fā)中難免會遇到分布式事務(wù)問題。大家經(jīng)常會聽到CAP原理,即一致性(Consistency)、可用性(Availability)、分區(qū)容錯性(Partition tolerance)三個(gè)指標(biāo)不可能同時(shí)滿足,而一致性是其中一個(gè)最大的難題。本文會從分布式事務(wù)產(chǎn)生背景開始,介紹常見分布式事務(wù)解決方案,最后會詳細(xì)介紹基于消息中間件實(shí)現(xiàn)最終一致性的兩種方案。

文章目錄

分布式事務(wù)產(chǎn)生背景

數(shù)據(jù)庫水平拆分

微服務(wù)拆分

分布式事務(wù)解決方案

TCC

XA事務(wù)(2PC)

最終一致性(消息事務(wù))

錯誤場景一

錯誤場景二

錯誤場景三

解決方案對比

最終一致性-本地消息表

最終一致性-RocketMq事務(wù)消息

兩階段提交

事務(wù)狀態(tài)定時(shí)回查

事務(wù)消息核心

最后

參考資料

分布式事務(wù)產(chǎn)生背景?

數(shù)據(jù)庫水平拆分

業(yè)務(wù)發(fā)展初期,許多業(yè)務(wù)采用單庫單表的方案來存儲數(shù)據(jù)。隨著業(yè)務(wù)的不斷演進(jìn)、發(fā)展,存儲數(shù)據(jù)量不斷變大,寫入QPS不斷增加,單庫的存儲、寫入都會存在瓶頸。因此我們對數(shù)據(jù)庫進(jìn)行水平拆分,即將完整的數(shù)據(jù)集,通過一定規(guī)則(比如按userIdorderId取模),將表中的某些行切分到一個(gè)數(shù)據(jù)庫,而另外的某些行又切分到其他的數(shù)據(jù)庫中。如下圖所示

數(shù)據(jù)庫水平拆分后,引來了如下幾個(gè)問題

1. 跨庫查詢較為復(fù)雜,如跨庫join性能差

2. 原本往一個(gè)數(shù)據(jù)庫中寫入數(shù)據(jù),現(xiàn)在可能變?yōu)橥鄠€(gè)庫中同時(shí)寫入數(shù)據(jù),這就是跨庫分布式事務(wù)問題

微服務(wù)拆分

在早期的一些系統(tǒng)中,不同業(yè)務(wù)模塊耦合在一個(gè)大的業(yè)務(wù)系統(tǒng)里,隨著業(yè)務(wù)的發(fā)展,單個(gè)業(yè)務(wù)系統(tǒng)擴(kuò)展性差,耦合度高的缺點(diǎn)越來越明顯。因此將不同業(yè)務(wù)模塊進(jìn)行拆分,構(gòu)建為松耦合、可獨(dú)立部署的一組服務(wù)。不同業(yè)務(wù)系統(tǒng)間通過諸如Dubbo、Spring Cloud等微服務(wù)框架進(jìn)行通信。

如圖所示,拆分后的業(yè)務(wù)應(yīng)用,是一個(gè)單一的、可獨(dú)立部署的組件,不同業(yè)務(wù)服務(wù)之間松耦合,可拓展。

隨著服務(wù)的拆分,分布式事務(wù)問題也不可避免,服務(wù)拆分之前,在單JVM進(jìn)程中可以通過Spring事務(wù)保證對單庫、多個(gè)業(yè)務(wù)表的操作在一個(gè)事務(wù)中。業(yè)務(wù)系統(tǒng)按照服務(wù)拆分之后,一個(gè)完整的業(yè)務(wù)操作往往需要通過Rpc調(diào)用多個(gè)服務(wù),如何保證多個(gè)服務(wù)間的數(shù)據(jù)一致性成為一個(gè)難題

分布式事務(wù)解決方案

TCC

TCC模式分布式事務(wù)解決方案,需要用戶根據(jù)自己的業(yè)務(wù)場景實(shí)現(xiàn) Try、Confirm 和 Cancel 三個(gè)操作,事務(wù)發(fā)起方在一階段執(zhí)行 Try 方式,在二階段提交執(zhí)行 Confirm 方法,二階段回滾執(zhí)行 Cancel 方法。

是一種應(yīng)用層面侵入業(yè)務(wù)的兩階段提交,每個(gè)操作含義如下

操作方法

含義

Try

完成數(shù)據(jù)檢查(一致性),預(yù)留資源(隔離性)

Confirm

確認(rèn)執(zhí)行業(yè)務(wù)操作,只使用try階段預(yù)留的資源,需保證冪等

Cancel

取消業(yè)務(wù)操作,釋放預(yù)留資源,需保證冪等

TCC模式的架構(gòu)圖如下

執(zhí)行步驟如下:

1. 主業(yè)務(wù)服務(wù)負(fù)責(zé)發(fā)起并完成整個(gè)事務(wù)操作。

2. 從業(yè)務(wù)服務(wù)提供TCC型業(yè)務(wù)操作。

3. 業(yè)務(wù)活動管理器(事務(wù)協(xié)調(diào)者)控制業(yè)務(wù)活動的一致性,它登記業(yè)務(wù)活動中的操作,并在業(yè)務(wù)活動提交時(shí)進(jìn)行confirm操作,在業(yè)務(wù)活動取消時(shí)進(jìn)行cancel操作,協(xié)調(diào)者會通過不斷重試的機(jī)制保障從業(yè)務(wù)的commit/cancel操作一定會執(zhí)行,故需保證TCC接口的冪等性

TCC方案也有不足之處,表現(xiàn)在以下幾個(gè)方面:

1. 對應(yīng)用的侵入性強(qiáng)。業(yè)務(wù)邏輯的每個(gè)分支都需要實(shí)現(xiàn)try、confirm、cancel三個(gè)操作,應(yīng)用侵入性較強(qiáng),改造成本高

2. 實(shí)現(xiàn)難度較大。需要按照網(wǎng)絡(luò)狀態(tài)、系統(tǒng)故障等不同的失敗原因?qū)崿F(xiàn)不同的回滾策略。為了滿足一致性的要求,confirmcancel接口必須實(shí)現(xiàn)冪等

3. 需要注意極端情況下的空回滾、防懸掛控制,對開發(fā)者/TCC中間件有較高要求

市面上的TCC中間件有:tcc-transaction

XA事務(wù)(2PC)

XA事務(wù)利用事務(wù)資源(比如Oracle、DB2這些商業(yè)數(shù)據(jù)庫)對 XA 協(xié)議的支持,以 XA 協(xié)議的機(jī)制來管理分支事務(wù)的一種事務(wù)模式,需要引入事務(wù)管理器作為分布式事務(wù)的全局協(xié)調(diào)者

如圖所示,XA協(xié)議是一種特殊的兩階段提交協(xié)議,分為兩個(gè)階段

1. 執(zhí)行階段:

可回滾:業(yè)務(wù) SQL 操作放在 XA 分支中進(jìn)行,由資源對 XA 協(xié)議的支持來保證可回滾

持久化:XA 分支完成后,執(zhí)行 XA prepare,同樣,由資源對 XA 協(xié)議的支持來保證持久化(即,之后任何意外都不會造成無法回滾的情況)

2. 完成階段:

分支提交:執(zhí)行 XA 分支的 commit分支回滾:執(zhí)行 XA 分支的 rollback

缺點(diǎn):XA目前在商業(yè)數(shù)據(jù)庫支持的比較理想,在mysql數(shù)據(jù)庫中支持的不太理想

目前市面上也出現(xiàn)了支持XA事務(wù)編程模型的中間件:Seata

同時(shí)Seata還支持一種特殊定制化,基本零侵入業(yè)務(wù)的AT模式(一種演進(jìn)版本的2PC模式)

最終一致性(消息事務(wù))

大部分的業(yè)務(wù)場景中,其實(shí)并不一定非得強(qiáng)求數(shù)據(jù)的強(qiáng)一致性,比如用戶在A系統(tǒng)進(jìn)行簽到,那么在B系統(tǒng)里進(jìn)行計(jì)算績效,只需保證A簽到成功后,B系統(tǒng)績效一定會計(jì)算,至于什么時(shí)候計(jì)算,是否立馬計(jì)算,其實(shí)并不重要。

其他諸如用戶在A系統(tǒng)下了單,在B系統(tǒng)用戶的積分一定得增加這種場景都是類似的,最終一致性也是解決分布式事務(wù)的一種常見方案。

很多場景下,我們“發(fā)消息”這個(gè)過程,目的往往是通知另外一個(gè)系統(tǒng)或者模塊去更新數(shù)據(jù),消息隊(duì)列中的“事務(wù)”,主要解決消息生產(chǎn)者和消息消費(fèi)者的數(shù)據(jù)一致性問題。

消息方案從本質(zhì)上講是將分布式事務(wù)轉(zhuǎn)換為多個(gè)本地事務(wù),然后依靠下游業(yè)務(wù)的重試機(jī)制達(dá)到最終一致性。基于消息的最終一致性方案性能比XA好很

錯誤場景一

看起來,好像消息事務(wù)就是這么點(diǎn)東西?上游更新完數(shù)據(jù),發(fā)個(gè)消息讓下游消費(fèi)下,下游也更新下自己的數(shù)據(jù),這不就完了?

如圖所示上游肯定要保證上游數(shù)據(jù)的處理和消息的發(fā)送在一個(gè)事務(wù)里,常見的偽代碼如下

@Transactionalpublic void execute(ActionExecuteParam param) { //更新本地?cái)?shù)據(jù)庫 mapper.update(param); //發(fā)送mq消息通知下游更新數(shù)據(jù) mqProducer.sendMsg(msg);}

上面的代碼對應(yīng)到執(zhí)行流程圖,即為如下所示,其中step3是容易被忽略的一步,如果把數(shù)據(jù)更新和發(fā)送mq消息放在一個(gè)事務(wù)里,那么實(shí)際數(shù)據(jù)的commit操作會在整個(gè)方法結(jié)束后(也就是消息完成后)進(jìn)行,假如此時(shí)數(shù)據(jù)庫操作出現(xiàn)報(bào)錯、超時(shí),那么消息已經(jīng)發(fā)出去了,下游數(shù)據(jù)已經(jīng)更新,但是上游數(shù)據(jù)卻沒有更新,出現(xiàn)了不一致

錯誤場景二

那么不加事務(wù)呢,行不行?如圖所示

此時(shí)假設(shè)step1數(shù)據(jù)更新完成后,step2進(jìn)行消息發(fā)送的時(shí)候,失敗了,或者超時(shí)異常了,那么step1的數(shù)據(jù)不會進(jìn)行回滾(數(shù)據(jù)已經(jīng)commit),此時(shí)下游數(shù)據(jù)未更新,一樣出現(xiàn)了不一致的情況

錯誤場景三

先發(fā)消息,再更新數(shù)據(jù)庫行不行?

這種Case就更明顯了,如果消息發(fā)送成功了,但是這時(shí)候系統(tǒng)重啟、數(shù)據(jù)庫超時(shí),都有可能導(dǎo)致消息發(fā)送成功(下游數(shù)據(jù)隨之更新),但是上游數(shù)據(jù)未更新,同樣會出現(xiàn)數(shù)據(jù)不一致

所以關(guān)鍵點(diǎn)是什么?只要上游執(zhí)行的數(shù)據(jù)變更操作和發(fā)送消息不是一個(gè)原子操作,即不在一個(gè)事務(wù)中完成,那么,無論先后順序如何,如何操作,都會出現(xiàn)數(shù)據(jù)不一致性問題

解決方案對比

用表格的形式總結(jié)下上面介紹的幾種分布式事務(wù)解決方案優(yōu)缺點(diǎn)

事務(wù)方案

優(yōu)點(diǎn)

缺點(diǎn)

2PC(XA事務(wù))

實(shí)現(xiàn)簡單

1、需要數(shù)據(jù)庫(一般是XA支持) 2、鎖粒度大,性能差

2PC(Seata ?AT模式)

實(shí)現(xiàn)簡單,業(yè)務(wù)侵入極低

需要引入、部署單獨(dú)Seata服務(wù),維護(hù)成本高

TCC

鎖粒度小,性能好

需要侵入業(yè)務(wù),實(shí)現(xiàn)較為復(fù)雜,復(fù)雜業(yè)務(wù)實(shí)現(xiàn)冪等有難度

消息事務(wù)

業(yè)務(wù)侵入小,無需編寫業(yè)務(wù)回滾補(bǔ)償邏輯

事務(wù)消息實(shí)現(xiàn)難度大,強(qiáng)依賴第三方中間件可靠性

考慮到消息中間件是平時(shí)開發(fā)中必不可少的中間件,同時(shí)大部分業(yè)務(wù)場景下并不要求分布式事務(wù)的強(qiáng)一致性,因此下面重點(diǎn)介紹基于消息中間件如何實(shí)現(xiàn)分布式事務(wù)的最終一致性

最終一致性-本地消息表

本地消息表的設(shè)計(jì)核心是將需要分布式處理的任務(wù)通過消息日志的方式來異步執(zhí)行。消息發(fā)送日志(記錄)可以存儲到本地文本、數(shù)據(jù)庫,再通過定時(shí)器自動或人工發(fā)起重試

即保證業(yè)務(wù)數(shù)據(jù)更新成功的同時(shí),一定會有一條對應(yīng)的消息記錄(消息發(fā)送狀態(tài)為待發(fā)送)在數(shù)據(jù)庫中,然后上游所在系統(tǒng)單獨(dú)啟動一個(gè)定時(shí)器去掃描該消息表,并將狀態(tài)為待發(fā)送的消息,投遞到消息服務(wù)器中,失敗重試,直到消息發(fā)送成功,那么就能解決數(shù)據(jù)更新和消息發(fā)送的原子性問題

整體流程圖如下

如果開發(fā)中使用的消息中間件并不支持事務(wù)消息的功能,那么本地消息表是一種不錯的最終一致性解決方案,那么缺點(diǎn)又是什么?顯而易見

業(yè)務(wù)方需要單獨(dú)設(shè)計(jì)消息表,及定時(shí)發(fā)送消息的定時(shí)器,增加了與業(yè)務(wù)無關(guān)的開發(fā)負(fù)擔(dān)

最終一致性-RocketMq事務(wù)消息

RocketMq 4.3版本中開源了事務(wù)消息,開發(fā)者可以借此來實(shí)現(xiàn)簡單的最終一致性。介紹事務(wù)消息之前,先拋出兩個(gè)核心概念:兩階段提交、事務(wù)狀態(tài)定時(shí)回查。

兩階段提交

關(guān)于兩階段提交的基本概念,貼上一張圖來簡單說明

因?yàn)橄l(fā)送是一個(gè)遠(yuǎn)程調(diào)用,由于網(wǎng)絡(luò)的不穩(wěn)定,無法和本地事務(wù)的執(zhí)行處于一個(gè)原子操作中,針對這個(gè)缺點(diǎn),RocketMQ基于兩階段提交協(xié)議做了如下改動

l?? 第一階段:生產(chǎn)者向MQ服務(wù)器發(fā)送事務(wù)消息(prepare半消息),服務(wù)端確認(rèn)后回調(diào)通知生產(chǎn)者執(zhí)行本地事務(wù)(此時(shí)消息為Prepare消息,存儲于RMQ_SYS_TRANS_HALF_TOPIC隊(duì)列中,不會被消費(fèi)者消費(fèi))

l?? 第二階段:生產(chǎn)者執(zhí)行完本地事務(wù)后(業(yè)務(wù)執(zhí)行完成,同時(shí)將消息唯一標(biāo)記,如transactionId與該業(yè)務(wù)執(zhí)行記錄同時(shí)入庫,方便事務(wù)回查),根據(jù)本地事務(wù)執(zhí)行結(jié)果,返回Commit/Rollback/Unknow狀態(tài)碼

1、服務(wù)端若收到Commit狀態(tài)碼,則將prepare消息變?yōu)樘峤?正常消息,可被消費(fèi)者消費(fèi))
2、收到Rollback則對消息進(jìn)行回滾(丟棄消息)
3、若狀態(tài)為Unknow,則等待MQ服務(wù)端定時(shí)發(fā)起消息狀態(tài)回查,超過一定重試次數(shù)或者超時(shí),消息會被丟棄

引用一張流程圖來說明消息事務(wù)的兩階段提交

其中prepare半消息是事務(wù)消息的核心,正常情況下生產(chǎn)者投遞到Broker的消息(除了延遲消息),會立馬被消費(fèi)者消息,而事務(wù)消息中,需要等待生產(chǎn)者執(zhí)行完本地事務(wù)后,才真正對半消息進(jìn)行投遞,這也就意味著,發(fā)送到Broker端的prepare半消息是不會被消費(fèi)者立馬消費(fèi)到的,為什么呢?

事務(wù)消息在Broker端進(jìn)行存儲落盤到CommitLog的時(shí)候,會有如下2點(diǎn)特殊處理

  • 修改消息topic為RMQ_SYS_TRANS_HALF_TOPIC,并備份消息原有topic,供后續(xù)commit消息時(shí)還原消息topic使用

  • 修改消息queueId為0,并備份消息原有queueId,供后續(xù)commit消息時(shí)還原消息queueId使用

修改完topic和queueId后,事務(wù)消息也會像普通消息一樣存儲在commitLog中

看到這,是不是就明白,為什么prepare消息在發(fā)送后不會被立馬消費(fèi)?因?yàn)橄?/strong>topic被修改了

事務(wù)狀態(tài)定時(shí)回查

在第二階段中,生產(chǎn)者在本地事務(wù)執(zhí)行完成后,需要向MQ服務(wù)器返回響應(yīng)狀態(tài)碼,發(fā)送狀態(tài)碼的過程也是通過Netty發(fā)送網(wǎng)絡(luò)請求,假設(shè)由于網(wǎng)絡(luò)原因發(fā)送失敗怎么辦?本地事務(wù)已經(jīng)提交/回滾了,但是Commit/Rollback狀態(tài)碼卻沒發(fā)出去,那么MQ服務(wù)器上這條prepare消息狀態(tài)豈不是無法被投遞/回滾

因此,MQ服務(wù)端會定時(shí)掃描存儲于RMQ_SYS_TRANS_HALF_TOPIC中的消息,若消息未被處理,則向消費(fèi)發(fā)送者發(fā)起回調(diào)檢查,檢查消息對應(yīng)本地事務(wù)執(zhí)行狀態(tài)。從而保證消息事務(wù)狀態(tài)最終能和本地事務(wù)的狀態(tài)一致。上圖中的4、5、6就是MQ服務(wù)端定時(shí)回查步驟。

事務(wù)消息核心

RocketMq通過引入prepare半消息機(jī)制、事務(wù)消息回查機(jī)制,保證生產(chǎn)者消息的發(fā)送與本地事務(wù)的執(zhí)行的原子性,將一個(gè)分布式大事務(wù)拆分成小事務(wù),減少了系統(tǒng)間的交互。同時(shí)通過MQ 的高可用特性(不丟失),及At-Least-Once 特性確保正確投遞的事務(wù)消息會在下游一定被消費(fèi),從而保證數(shù)據(jù)的最終一致性。

最后

分布式事務(wù)作為平時(shí)開發(fā)中不可避免的一個(gè)技術(shù)難點(diǎn),我們有必要了解其常見的解決方案。又因?yàn)橄⒅虚g件是開發(fā)中不可或缺的一個(gè)中間件,通過消息中間件來實(shí)現(xiàn)最終一致性是一種成本較低的可靠方案,希望本文介紹的基于消息中間件實(shí)現(xiàn)的最終一致性方案原理,對大家平時(shí)開發(fā)會有所幫助。至于具體的事務(wù)消息使用例子,大家可以參考RocketMq官網(wǎng),由于篇幅原因,這里不再過多介紹。

同時(shí),阿里開源的Seata,包含了上述常見的幾種分布式解決方案,如TCC、XA、AT(一種零侵入、業(yè)務(wù)層面實(shí)現(xiàn)補(bǔ)償、回滾的方案)、Saga(適用于長事務(wù)的最終一致性方案),具有較高的學(xué)習(xí)價(jià)值,有興趣的同學(xué)可以看看其實(shí)現(xiàn)原理。

參考資料

http://seata.io/zh-cn/index.html
https://github.com/apache/rocketmq
https://github.com/changmingxie/tcc-transaction


招聘時(shí)間:

普惠公眾平臺、carbo團(tuán)隊(duì)持續(xù)招人,有興趣的可以投遞簡歷到:tomchenyin@didiglobal.com

職位描述

1、負(fù)責(zé)服務(wù)管理方向流程編排服務(wù)、任務(wù)平臺的開發(fā)與維護(hù)。

2、參與項(xiàng)目的系統(tǒng)分析,設(shè)計(jì)工作,承擔(dān)核心功能,公共核心架構(gòu)模塊的代碼編寫。

3、解決各種疑難雜癥,系統(tǒng)優(yōu)化,并且完成產(chǎn)品、平臺和組件的沉淀。

4、負(fù)責(zé)團(tuán)隊(duì)穩(wěn)定性建設(shè)工作。

任職要求

1、本科以上學(xué)歷,計(jì)算機(jī)軟件專業(yè),3 年以上 JAVA 開發(fā)經(jīng)驗(yàn)。

2、JAVA 基礎(chǔ)扎實(shí),熟悉 io/nio,多線程等基礎(chǔ)知識,熟悉分布式,緩存,消息隊(duì)列等主流技術(shù)。熟悉 spring 、mybatis 等主流框架,熟悉常用的設(shè)計(jì)模式。

3、具備較強(qiáng)的領(lǐng)域建模能力和業(yè)務(wù) sense。

4、具備較強(qiáng)的抗壓能力和良好的溝通技巧,優(yōu)秀的團(tuán)隊(duì)合作精神,善于學(xué)習(xí),深度思考。

總結(jié)

以上是生活随笔為你收集整理的一致 先验分布 后验分布_分布式事务常见解决方案与最终一致性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。