新聞中心
一、背景
MQ組件是系統(tǒng)架構(gòu)里必不可少的一門利器,設(shè)計(jì)層面可以降低系統(tǒng)耦合度,高并發(fā)場(chǎng)景又可以起到削峰填谷的作用,從單體應(yīng)用到集群部署方案,再到現(xiàn)在的微服務(wù)架構(gòu),MQ憑借其優(yōu)秀的性能和高可靠性,得到了廣泛的認(rèn)可。
隨著數(shù)據(jù)量增多,系統(tǒng)壓力變大,開始出現(xiàn)這種現(xiàn)象:數(shù)據(jù)庫已經(jīng)更新了,但消息沒發(fā)出來,或者消息先發(fā)了,但后來數(shù)據(jù)庫更新失敗了,結(jié)果研發(fā)童鞋各種數(shù)據(jù)修復(fù),這種生產(chǎn)問題出現(xiàn)的概率不大,但讓人很郁悶。這個(gè)其實(shí)就是數(shù)據(jù)庫事務(wù)與MQ消息的一致性問題,簡(jiǎn)單來講,數(shù)據(jù)庫的事務(wù)跟普通MQ消息發(fā)送無法直接綁定與數(shù)據(jù)庫事務(wù)綁定在一起,例如上面提及的兩種問題場(chǎng)景:
創(chuàng)新互聯(lián)主要從事成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)桂東,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
- 數(shù)據(jù)庫事務(wù)提交后發(fā)送MQ消息;
- MQ消息先發(fā),然后再提交數(shù)據(jù)庫事務(wù)。
場(chǎng)景1的問題是數(shù)據(jù)庫事務(wù)可能剛剛提交,服務(wù)器就宕機(jī)了,MQ消息沒發(fā)出去,場(chǎng)景2的問題就是MQ消息發(fā)送出去了,但數(shù)據(jù)庫事務(wù)提交失敗,又沒辦法追加已經(jīng)發(fā)出去的MQ消息,結(jié)果導(dǎo)致數(shù)據(jù)沒更新,下游已經(jīng)收到消息,最終事務(wù)出現(xiàn)不一致的情況。
二、事務(wù)消息的引出
我們以微服務(wù)架構(gòu)的購物場(chǎng)景為例,參照一下RocketMQ官方的例子,用戶A發(fā)起訂單,支付100塊錢操作完成后,能得到100積分,賬戶服務(wù)和會(huì)員服務(wù)是兩個(gè)獨(dú)立的微服務(wù)模塊,有各自的數(shù)據(jù)庫,按照上文提及的問題可能性,將會(huì)出現(xiàn)這些情況:
- 如果先扣款,再發(fā)消息,可能錢剛扣完,宕機(jī)了,消息沒發(fā)出去,結(jié)果積分沒增加。
- 如果先發(fā)消息,再扣款,可能積分增加了,但錢沒扣掉,白送了100積分給人家。
- 錢正??哿?,消息也發(fā)送成功了,但會(huì)員服務(wù)實(shí)例消費(fèi)消息出現(xiàn)問題,結(jié)果積分沒增加。
由此引出的是數(shù)據(jù)庫事務(wù)與MQ消息的事務(wù)一致性問題,rocketmq事務(wù)消息解決的問題:解決本地事務(wù)執(zhí)行與消息發(fā)送的原子性問題。這里界限一定要明白,是確保MQ生產(chǎn)端正確無誤地將消息發(fā)送出來,沒有多發(fā),也不會(huì)漏發(fā)。但至于發(fā)送后消費(fèi)端有沒有正常的消費(fèi)掉(如上面提及的第三種情況,錢正??哿?,消息也發(fā)了,但下游消費(fèi)出問題導(dǎo)致積分不對(duì)),這種異常場(chǎng)景將由MQ消息消費(fèi)失敗重試機(jī)制來保證,不在此次的討論范圍內(nèi)。
常用的MQ組件針對(duì)此場(chǎng)景都有自己的實(shí)現(xiàn)方案,如ActiveMQ使用AMQP協(xié)議(二階提交方式)保證消息正確發(fā)送,這里我們以RocketMQ為重點(diǎn)進(jìn)行學(xué)習(xí)。
三、RocketMQ事務(wù)消息設(shè)計(jì)思路
根據(jù)CAP理論,RocketMQ事務(wù)消息通過異步確保方式,保證事務(wù)的最終一致性。設(shè)計(jì)流程上借鑒兩階段提交理論,流程圖如下:
- 應(yīng)用模塊遇到要發(fā)送事務(wù)消息的場(chǎng)景時(shí),先發(fā)送prepare消息給MQ。
- prepare消息發(fā)送成功后,應(yīng)用模塊執(zhí)行數(shù)據(jù)庫事務(wù)(本地事務(wù))。
- 根據(jù)數(shù)據(jù)庫事務(wù)執(zhí)行的結(jié)果,再返回Commit或Rollback給MQ。
- 如果是Commit,MQ把消息下發(fā)給Consumer端,如果是Rollback,直接刪掉prepare消息。
- 第3步的執(zhí)行結(jié)果如果沒響應(yīng),或是超時(shí)的,啟動(dòng)定時(shí)任務(wù)回查事務(wù)狀態(tài)(最多重試15次,超過了默認(rèn)丟棄此消息),處理結(jié)果同第4步。
- MQ消費(fèi)的成功機(jī)制由MQ自己保證。
四、RocketMQ事務(wù)消息實(shí)現(xiàn)流程
以RocketMQ 4.5.2版本為例,事務(wù)消息有專門的一個(gè)隊(duì)列RMQ_SYS_TRANS_HALF_TOPIC,所有的prepare消息都先往這里放,當(dāng)消息收到Commit請(qǐng)求后,就把消息再塞到真實(shí)的Topic隊(duì)列里,供Consumer消費(fèi),同時(shí)向RMQ_SYS_TRANS_OP_HALF_TOPIC塞一條消息。簡(jiǎn)易流程圖如下:
上述流程中,請(qǐng)?jiān)试S我這樣劃分模塊職責(zé):
- RocketMQ Client即我們工程中導(dǎo)入的依賴jar包,RocketMQ Broker端即部署的服務(wù)端,NameServer暫未體現(xiàn)。
- 應(yīng)用模塊成對(duì)出現(xiàn),上游為事務(wù)消息生產(chǎn)端,下游為事務(wù)消息消費(fèi)端(事務(wù)消息對(duì)消費(fèi)端是透明的,與普通消息一致)。
應(yīng)用模塊的事務(wù)因?yàn)橹袛啵蚴瞧渌木W(wǎng)絡(luò)原因,導(dǎo)致無法立即響應(yīng)的,RocketMQ當(dāng)做UNKNOW處理,RocketMQ事務(wù)消息還提供了一個(gè)補(bǔ)救方案:定時(shí)查詢事務(wù)消息的數(shù)據(jù)庫事務(wù)狀態(tài)
簡(jiǎn)易流程圖如下:
五、結(jié)束語
本篇簡(jiǎn)單介紹了事務(wù)消息的解決的場(chǎng)景和職責(zé)的界限,基本的設(shè)計(jì)思路和流程,在此借鑒學(xué)習(xí)了RocketMQ作者的圖稿,然后挑了部分代碼作簡(jiǎn)要的講解,還是自己的刨坑過程,文章內(nèi)有任何不正確或不詳盡之處請(qǐng)留言指導(dǎo),謝謝。
標(biāo)題名稱:RocketMQ事務(wù)消息學(xué)習(xí)及刨坑過程
本文URL:http://fisionsoft.com.cn/article/jocjsc.html