在這篇文章中我們將介紹RocketMQ的事務(wù)消息相關(guān)的內(nèi)容,并通過(guò)一些實(shí)踐和大家一起來(lái)探索下事務(wù)消息如何解決分布式系統(tǒng)中的分布式事務(wù)問(wèn)題。
阜新ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話(huà)聯(lián)系或者加微信:18980820575(備注:SSL證書(shū)合作)期待與您的合作!
事務(wù)消息特性可以看作是兩階段協(xié)議的消息實(shí)現(xiàn)方式,用以確保在以消息中間件解耦的分布式系統(tǒng)中本地事務(wù)的執(zhí)行和消息的發(fā)送,可以以原子的方式進(jìn)行。
舉個(gè)例子,以某互聯(lián)網(wǎng)公司的用戶(hù)余額充值為例,因?yàn)橛谐浞祷顒?dòng)(充值100元贈(zèng)送20元),優(yōu)惠比較大,用戶(hù)Joe禁不住誘惑用支付寶向自己的余額賬戶(hù)充值了100元,支付成功后Joe的余額賬戶(hù)有了120元錢(qián)。
而該公司的關(guān)于用戶(hù)余額充值的系統(tǒng)設(shè)計(jì)是這樣的:
在這個(gè)設(shè)計(jì)流程中,該公司通過(guò)自建支付系統(tǒng)完成用戶(hù)Joe的支付寶扣款操作,成功后需要更新支付流水的狀態(tài),因?yàn)橛脩?hù)的余額賬戶(hù)系統(tǒng)與支付系統(tǒng)之間通過(guò)MQ解耦了,所以支付系統(tǒng)在完成支付流水狀態(tài)更新后需要通過(guò)發(fā)送MQ消息到消息中間件服務(wù),然后用戶(hù)余額系統(tǒng)作為消費(fèi)者通過(guò)消息消費(fèi)的方式完成用戶(hù)余額的增加操作。
這里有個(gè)問(wèn)題:“支付系統(tǒng)如何確保這筆余額充值消息一定會(huì)成功發(fā)送到MQ,并且用戶(hù)余額系統(tǒng)一定能處理成功呢”?如果支付系統(tǒng)在完成支付訂單狀態(tài)更新后,MQ消息發(fā)送失敗或者用戶(hù)余額系統(tǒng)消息處理失敗的話(huà),都會(huì)導(dǎo)致Joe支付扣款成功,而自己的余額賬戶(hù)卻沒(méi)到賬的情況發(fā)生。
為了解決這個(gè)問(wèn)題,按照目前的系統(tǒng)設(shè)計(jì)是需要“支付系統(tǒng)-MQ服務(wù)-用戶(hù)余額系統(tǒng)”三者的處理滿(mǎn)足數(shù)據(jù)的一致性要求。例如,如果支付系統(tǒng)感知到消息發(fā)送失敗后還可以進(jìn)行重新投遞,從而確保支付系統(tǒng)與用戶(hù)余額數(shù)據(jù)的最終一致性。
而上述問(wèn)題就是事務(wù)消息要解決的問(wèn)題,在具體了解RocketMQ提供的事務(wù)消息機(jī)制之前,我們先來(lái)看下在RocketMQ的早期版本不支持事務(wù)消息,或者因?yàn)闅v史原因選擇的消息中間件本身就不支持事務(wù)消息的情況下,一些大公司是怎么解決這個(gè)問(wèn)題的?
早期為了實(shí)現(xiàn)基于MQ異步調(diào)用的多個(gè)服務(wù)間,業(yè)務(wù)邏輯執(zhí)行要么一起成功、要么一起失敗,具備事務(wù)特點(diǎn),通常會(huì)采用可靠消息最終一致性方案,來(lái)實(shí)現(xiàn)分布式事務(wù)。還是以Joe充值這件事來(lái)舉例,可靠消息方案實(shí)現(xiàn)過(guò)程如下:
在可靠消息最終一致性方案中,為了實(shí)現(xiàn)分布式事務(wù),需要確保上游服務(wù)本地事務(wù)的處理與MQ消息的投遞具有原子性,也就是說(shuō)上游服務(wù)本地事務(wù)處理成功后要確保消息一定要成功投遞到MQ服務(wù),否則消息就不應(yīng)該被投遞到MQ服務(wù);同樣,被成功投遞到MQ服務(wù)的消息,也一定要被下游服務(wù)成功處理,否則就需要重新投遞MQ消息。
為了實(shí)現(xiàn)雙向的原子性,可靠消息服務(wù)需要對(duì)消息進(jìn)行狀態(tài)標(biāo)記,與此同時(shí)還需要對(duì)消息進(jìn)行狀態(tài)檢查,從而實(shí)現(xiàn)重新投遞及消息狀態(tài)的最終一致性。核心流程說(shuō)明如下:
1、上游服務(wù)(支付系統(tǒng))如何確保完成自身支付成功狀態(tài)更新后消息100%的能夠投遞到下游服務(wù)(用戶(hù)余額系統(tǒng))指定的Topic中?
在這個(gè)流程中上游服務(wù)在進(jìn)行本地?cái)?shù)據(jù)庫(kù)事務(wù)操作前,會(huì)先發(fā)送一個(gè)狀態(tài)為“待確認(rèn)”的消息至可靠消息服務(wù),而不是直接將消息投遞到MQ服務(wù)的指定Topic。可靠消息服務(wù)此時(shí)會(huì)將該消息記錄到自身服務(wù)的消息數(shù)據(jù)庫(kù)中(消息狀態(tài)為->待確認(rèn)),完成后可靠消息服務(wù)會(huì)回調(diào)上游服務(wù)表示收到了消息,你們可以進(jìn)行本地事務(wù)的操作了。
之后上游服務(wù)就會(huì)開(kāi)啟本地?cái)?shù)據(jù)庫(kù)事務(wù)執(zhí)行業(yè)務(wù)邏輯操作,這里支付系統(tǒng)就會(huì)將該筆支付訂單狀態(tài)更新為“已成功”。(注意,這里只是舉個(gè)示例場(chǎng)景,在真正的實(shí)踐中一般是不會(huì)把支付訂單本身的狀態(tài)與業(yè)務(wù)端回調(diào)放在一個(gè)事務(wù)流程中的,關(guān)于這部分的詳細(xì)說(shuō)明我們?cè)谙旅娴膱?chǎng)景說(shuō)明中再討論)。
如果上游服務(wù)本地?cái)?shù)據(jù)庫(kù)事務(wù)執(zhí)行成功,則繼續(xù)向可靠消息服務(wù)發(fā)送消息確認(rèn)消息,此時(shí)可靠消息服務(wù)就會(huì)正式將消息投遞到MQ服務(wù),并且同時(shí)更新消息數(shù)據(jù)庫(kù)中的消息狀態(tài)為“已發(fā)送”。(注意,這里可靠消息服務(wù)更新消息狀態(tài)與投遞消息至MQ也必須是在一個(gè)原子操作中,即消息投遞成功則一定要將消息狀態(tài)更新為“已發(fā)送”,所以在編程的細(xì)節(jié)中,可靠消息服務(wù)一般會(huì)先更新消息狀態(tài),然后再進(jìn)行消息投遞,這樣即使消息投遞失敗,也可以對(duì)消息狀態(tài)進(jìn)行回滾->“待確認(rèn)”,相反如果先進(jìn)行消息投遞再更新消息狀態(tài),可能就不好控制了)。
相反,如果上游本地?cái)?shù)據(jù)庫(kù)事務(wù)執(zhí)行失敗,則需要向可靠消息服務(wù)發(fā)送消息刪除消息,可靠消息服務(wù)此時(shí)就會(huì)將消息刪除,這樣就意味著事務(wù)在上游消息投遞過(guò)程中就被回滾了,而流程也就此結(jié)束了,此時(shí)上游服務(wù)可以需要通過(guò)業(yè)務(wù)邏輯的設(shè)計(jì)進(jìn)行重發(fā),這個(gè)就不再分布式事務(wù)的討論范疇了。
說(shuō)到這里,大家可能會(huì)有疑問(wèn)了!因?yàn)樵谏鲜雒枋鲋?,即使上游服?wù)本地?cái)?shù)據(jù)庫(kù)事務(wù)執(zhí)行成功了,但是在發(fā)送確認(rèn)消息至可靠消息服務(wù)的過(guò)程中,以及可靠消息服務(wù)在投遞消息至MQ服務(wù)的過(guò)程中,還是會(huì)存在失敗的風(fēng)險(xiǎn),這樣的話(huà)還是會(huì)導(dǎo)致支付服務(wù)更新了狀態(tài),但是用戶(hù)余額系統(tǒng)連消息都沒(méi)有收到的情況發(fā)生?
實(shí)際上,實(shí)現(xiàn)數(shù)據(jù)一致性是一個(gè)復(fù)雜的活。在這個(gè)方案中可靠消息服務(wù)作為基礎(chǔ)性的服務(wù)除了執(zhí)行正常的邏輯外,還得處理復(fù)雜的異常場(chǎng)景。在實(shí)現(xiàn)過(guò)程中可靠消息服務(wù)需要啟動(dòng)相應(yīng)的后臺(tái)線(xiàn)程,不斷輪訓(xùn)消息的狀態(tài),這里會(huì)輪訓(xùn)消息狀態(tài)為“待確認(rèn)”的消息,并判斷該消息的狀態(tài)的持續(xù)時(shí)間是否超過(guò)了規(guī)定的時(shí)間,如果超過(guò)規(guī)定時(shí)間的消息還處于“待確認(rèn)”的狀態(tài),就會(huì)觸發(fā)上游服務(wù)狀態(tài)詢(xún)問(wèn)機(jī)制。
可靠消息服務(wù)就會(huì)調(diào)用上游服務(wù)提供的相關(guān)借口,詢(xún)問(wèn)這筆消息的處理情況,如果這筆消息在上游服務(wù)處理成功,則后臺(tái)線(xiàn)程就會(huì)繼續(xù)觸發(fā)上圖中的步驟5,更新消息狀態(tài)為“已發(fā)送”并投遞消息至MQ服務(wù);反之如果這筆消息上游服務(wù)處理失敗,可靠消息服務(wù)則會(huì)進(jìn)行消息刪除。通過(guò)這樣以上機(jī)制就確保了“上游服務(wù)本地事務(wù)成功處理+消息成功投遞”處于一個(gè)原子操作了。
2、下游服務(wù)(用戶(hù)余額系統(tǒng))如何確保對(duì)MQ服務(wù)Topic消息的消費(fèi)100%都能處理成功?
在1的過(guò)程中,確保了上游服務(wù)邏輯處理與MQ消息的投遞具備原子性,那么當(dāng)消息被成功投遞到了MQ服務(wù)的指定Topic后,下游服務(wù)如何才能確保消息的消費(fèi)一定能被成功處理呢?
在正常的流程中,下游服務(wù)等待消費(fèi)Topic的消息并進(jìn)行自身本地?cái)?shù)據(jù)庫(kù)事務(wù)的處理,如果處理成功則會(huì)主動(dòng)通知可靠消息服務(wù),可靠消息服務(wù)此時(shí)就會(huì)將消息的狀態(tài)更新為“已完成”;反之,處理失敗下游服務(wù)就無(wú)法再主動(dòng)向可靠消息服務(wù)發(fā)送通知消息了。
此時(shí),與消息投遞過(guò)程中的異常邏輯一樣,可靠消息服務(wù)也會(huì)啟動(dòng)相應(yīng)的后臺(tái)線(xiàn)程,輪詢(xún)一直處于“已發(fā)送”狀態(tài)的消息,判斷狀態(tài)持續(xù)時(shí)間是否超過(guò)了規(guī)定時(shí)間,如果超時(shí),可靠消息服務(wù)就會(huì)再次向MQ服務(wù)投遞此消息,從而確保消息能被再次消費(fèi)處理。(注意,也可能出現(xiàn)下游服務(wù)處理成功,但是通知消息發(fā)送失敗的情況,所以為了確保冪等,下游服務(wù)也需要在業(yè)務(wù)邏輯上做好相應(yīng)的防重處理)。
在
本文名稱(chēng):如何基于RocketMQ的事務(wù)消息特性實(shí)現(xiàn)分布式系統(tǒng)的最終一致性?
網(wǎng)址分享:http://jinyejixie.com/article40/ggegeo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷(xiāo)推廣、定制開(kāi)發(fā)、網(wǎng)頁(yè)設(shè)計(jì)公司、網(wǎng)站收錄、虛擬主機(jī)、搜索引擎優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)