事務(wù)消息

目錄
一评姨、概念
二难述、支付和發(fā)送MQ的一致性?
三、RocketMQ的事務(wù)消息
四吐句、ebay通用方案: 本地消息表 + MQ
五胁后、小結(jié)

一、概念

image-20211031090718024.png
#1.為什么需要事務(wù)消息?
#2.業(yè)務(wù)為什么這樣設(shè)計? 解耦: 計算手續(xù)費可以離線計算,利用MQ解耦支付和計算手續(xù)費流程
(1)流程主要涉及三個步驟:
--支付成功,更新訂單數(shù)據(jù)
--發(fā)送消息給 MQ
--手續(xù)費系統(tǒng)拉取消息,計算手續(xù)費入庫
(2)任何一個步驟失敗,都會導(dǎo)致數(shù)據(jù)不一致
--要么訂單數(shù)據(jù)更新了,手續(xù)費數(shù)據(jù)沒有生成
--要么手續(xù)費生成,但是訂單數(shù)據(jù)沒更新
(3)消息的消費比較簡單,若消費失敗,只要我們沒有提交消息確認(rèn),那么MQ服務(wù)器將會自動重試
(4)最大的問題: 如何保證支付和發(fā)送MQ的一致性?
--1.發(fā)送MQ 2.更新支付數(shù)據(jù): 提交事務(wù)但是回滾了,此時消息發(fā)送出去無法撤回,手續(xù)費計算并入庫了!數(shù)據(jù)不一致
--1.更新支付數(shù)據(jù)  2.發(fā)送MQ : 

二嗦枢、支付和發(fā)送MQ的一致性?

image-20211031000505388.png
#1.先更新支付數(shù)據(jù),后發(fā)送MQ,是不是看不出什么問題
(1)偽代碼
// 開始事務(wù)
try {
  // 1.執(zhí)行數(shù)據(jù)庫操作
  // 2.發(fā)送 mq 消息
  // 3.提交事務(wù)
}catch (Exception e){
  // 4.回滾事務(wù)
}

(2)存在一種情況:由于網(wǎng)絡(luò)原因未收到MQ Server的響應(yīng)結(jié)果,認(rèn)為消息發(fā)送失敗導(dǎo)致回滾,實際消息已經(jīng)存儲在MQ Server了,手續(xù)費系統(tǒng)正常且計算后入庫,兩邊DB顯示數(shù)據(jù)不一致了


#2.MQ發(fā)送失敗不是可以重試嗎?
(1)消息重試如果耦合在事務(wù)中,顯然會拉長數(shù)據(jù)庫事務(wù)執(zhí)行時間,事務(wù)持有鎖時間過長,影響整體數(shù)據(jù)庫的吞吐量
(2)實際業(yè)務(wù),不太建議將消息耦合到數(shù)據(jù)庫事務(wù)中

三攀芯、RocketMQ的事務(wù)消息

image-20211031001104843.png
#1.概念
(1)可實現(xiàn)分布式事務(wù): 事務(wù)操作和消息發(fā)送要么都成功,要么都失敗

#2.實現(xiàn)原理
(1)first先發(fā)送一個半half消息到MQ中,通知開啟一個事務(wù)
注意:這里的半消息并不是說內(nèi)容不完整,實際包含所有的消息內(nèi)容,半消息和普通消息唯一的區(qū)別在于事務(wù)提交之前message對于consumer來說是"不可見"的
(2)half message 發(fā)送成功,那么可以根據(jù)事務(wù)的執(zhí)行結(jié)果再決定提交/回滾(事務(wù)|消息)
(3)
--若事務(wù)提交成功,那么發(fā)送確認(rèn)消息給MQ,那么手續(xù)費系統(tǒng)可以成功消費這個message
--若事務(wù)被回滾,發(fā)送回滾通知給MQ,那么MQ會將這個half message刪除
1419561-20200330075826122-1719090786.jpg
#3.那提交事務(wù)/回滾事務(wù)過程中 失敗怎么樣?
(1)MQ有"事務(wù)反查"機制,我們需要注冊一個回調(diào)接口,MQ會定時反查本地事務(wù)狀態(tài),根據(jù)結(jié)果決定回滾還是提交事務(wù)
(2)需要繼承 TransactionListener 注解回調(diào)接口
executeLocalTransaction 方法執(zhí)行本地事務(wù)
checkLocalTranscation 用來執(zhí)行檢查本地事務(wù)
(3)消息反查次數(shù)過多,導(dǎo)致半消息隊列堆積,影響性能
--RocketMQ 默認(rèn)將單個消息的檢查次數(shù)限制為 15 次,當(dāng)檢查次數(shù)超過最大次數(shù)后,RocketMQ 將會丟棄消息并且打印錯誤日志净宵。
--修改 broker 配置文件
# N為最大檢查次數(shù)
transactionCheckMax=N
--若想自定義丟棄消息行為敲才,需要修改 RocketMQ broker 端代碼裹纳,繼承 AbstractTransactionalMessageCheckListener 重寫 resolveDiscardMsg 方法择葡,加入自定義邏輯。
(4)反查時間設(shè)置
--設(shè)置 MQ 服務(wù)端多久之后開始反查事務(wù)消息(自事務(wù)消息保存成功之后開始計算),修改 broker 配置文件
#用于控制事務(wù)性消息檢查間隔, broker 每隔 5s 檢查一次事務(wù)消息剃氧,如果此時事務(wù)消息到 MQ 服務(wù)端時間還未超過 60s敏储,此時將不會反查,直到時間大于 60s朋鞍。
transactionTimeout=60000  //  單位為 ms,默認(rèn)為 60s
transactionCheckInterval=5000 // 每隔 5s 檢查一次事務(wù)消息

#4.偽代碼如下
public static class TransactionListenerImpl implements TransactionListener {
        /**
         * 半消息發(fā)送成功將會自動執(zhí)行該邏輯
         */
        @Override
        public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
            // 執(zhí)行本地事務(wù)
            try {
            } catch (Exception e) {
                System.out.println("本地事務(wù)執(zhí)行異常");
            }
            // 異常情況返回未知狀態(tài)
            return LocalTransactionState.UNKNOW;
        }

        /***
         * 若提交/回滾事務(wù)消息失敗已添,rocketmq 自動反查事務(wù)狀態(tài)
         * @param msg
         * @return
         */
        @Override
        public LocalTransactionState checkLocalTransaction(MessageExt msg) {
            try {
                if (isSuccess) {
                    // 本地事務(wù)執(zhí)行成功,提交半消息
                } else {
                    // 本地事務(wù)執(zhí)行成功滥酥,回滾半消息
                }
            } catch (Exception e) {
            }
            // 異常情況返回未知狀態(tài)
            return LocalTransactionState.UNKNOW;
        }
    }

四更舞、ebay通用方案: 本地消息表 + MQ

image-20211031083104157.png
#1.例子
(1)若有兩個微服務(wù)交互,支付服務(wù)和手續(xù)費服務(wù)坎吻,支付服務(wù)用于更新支付狀態(tài)缆蝉,手續(xù)費服務(wù)從MQ接受支付成功消息計算手續(xù)費,兩者不同庫表
(2)消息的消費有ack可保證不會重復(fù)消費,難點在于如何保證支付service + 消費一致

#2.本地消息表保證支付service + 消息發(fā)送的一致性?
(1)本地事務(wù)新增"消息日志",(支付表和消息日志表通過本地事務(wù)保證一致,保證原子性)
mysql begin transaction
// 1.支付service
// 2.存儲本地消息
commit transaction

(2)定時掃描消息日志
第一步已經(jīng)將消息寫到了消息日志表,可以啟動獨立線程定時任務(wù)job對消息日志表進行掃描
--掃描到記錄并成功發(fā)送到MQ Server,則刪除該消息日志
--若MQ未反饋發(fā)送成功則等到下一個周期重試

(3)如何保證consumer一定能消費到message?
--MQ有ack消息確認(rèn)機制,consumer接受到消息并完成業(yè)務(wù)流程向MQ發(fā)送ack,說明consumer消費message完成,MQ不再推送message,否則producer不斷重試向consumer發(fā)送mesaage
--因為消息中間件可能會重復(fù)投遞此消息,那么手續(xù)費service則需要保證冪等

五、小結(jié)

#1.可靠消息最終一致性
(1)保證message從producer傳遞到consumer的一致性
(2)注意兩個問題
--本地事務(wù)和消息發(fā)送的原子性問題
--consumer消費message的可靠性


#2.使用場景
(1)異步,解耦:同步事務(wù)變成了消息執(zhí)行的異步操作,避免了分布式事務(wù)同步阻塞,并實現(xiàn)了兩個微服務(wù)的解耦
(2)執(zhí)行周期長,實時性不高:可靠消息一致性適合執(zhí)行周期長且實時性不高的場景

ref:
還不知道事務(wù)消息嗎瘦真?這篇文章帶你全面掃盲刊头! - 樓下小黑哥 - 博客園 (cnblogs.com)
小黑十一點半 (studyidea.cn)
分布式事務(wù)有這一篇就夠了! - 知乎 (zhihu.com)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诸尽,一起剝皮案震驚了整個濱河市原杂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌您机,老刑警劉巖穿肄,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件年局,死亡現(xiàn)場離奇詭異,居然都是意外死亡咸产,警方通過查閱死者的電腦和手機某宪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锐朴,“玉大人兴喂,你說我怎么就攤上這事》僦荆” “怎么了衣迷?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酱酬。 經(jīng)常有香客問我壶谒,道長,這世上最難降的妖魔是什么膳沽? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任汗菜,我火速辦了婚禮,結(jié)果婚禮上挑社,老公的妹妹穿的比我還像新娘陨界。我一直安慰自己,他們只是感情好痛阻,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布菌瘪。 她就那樣靜靜地躺著,像睡著了一般阱当。 火紅的嫁衣襯著肌膚如雪俏扩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天弊添,我揣著相機與錄音录淡,去河邊找鬼。 笑死油坝,一個胖子當(dāng)著我的面吹牛嫉戚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播免钻,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼彼水,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了极舔?” 一聲冷哼從身側(cè)響起凤覆,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拆魏,沒想到半個月后盯桦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慈俯,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年拥峦,在試婚紗的時候發(fā)現(xiàn)自己被綠了贴膘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡略号,死狀恐怖刑峡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玄柠,我是刑警寧澤突梦,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站羽利,受9級特大地震影響宫患,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜这弧,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一娃闲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匾浪,春花似錦皇帮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梯浪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瓢娜,已是汗流浹背挂洛。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留眠砾,地道東北人虏劲。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像褒颈,于是被迫代替她去往敵國和親柒巫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容