一、MQ數(shù)據(jù)交互
MQ怎么保證消息不丟失暗甥?首先先確認(rèn)哪些場(chǎng)景會(huì)丟消息:一條消息從生產(chǎn)到消費(fèi)主要經(jīng)歷下面幾個(gè)主要階段框往。
二岖沛、生產(chǎn)階段
2.1 定義
消息在Producer創(chuàng)建暑始,經(jīng)過(guò)網(wǎng)絡(luò)傳輸發(fā)送到Broker端。
2.2 說(shuō)明
在生產(chǎn)階段婴削,消息隊(duì)列通過(guò)最常用的請(qǐng)求確認(rèn)機(jī)制廊镜,來(lái)保證消息的可靠傳遞。當(dāng)你的代碼調(diào)用發(fā)送消息方法時(shí)唉俗,消息隊(duì)列的客戶端會(huì)把消息發(fā)送到 Broker嗤朴,Broker 收到消息后,會(huì)給客戶端返回一個(gè)確認(rèn)響應(yīng)虫溜,表明消息已經(jīng)收到了雹姊。客戶端收到響應(yīng)后衡楞,完成了一次正常消息的發(fā)送吱雏。只要 Producer 收到了 Broker 的Ack響應(yīng),就可以保證消息在生產(chǎn)階段不會(huì)丟失瘾境。有些消息隊(duì)列在長(zhǎng)時(shí)間沒(méi)收到發(fā)送確認(rèn)響應(yīng)后歧杏,會(huì)自動(dòng)重試,如果重試再失敗迷守,就會(huì)以返回值或者異常的方式告知用戶犬绒。
2.3 kafka為例
這里以kafka為例舉例說(shuō)明一下:kafka生產(chǎn)者有個(gè)參數(shù)acks參數(shù)配置。
2.3.1 acks=0
acks = 0如果設(shè)置為零兑凿,那么生產(chǎn)者將完全不會(huì)管服務(wù)器是否收到消息凯力,該記錄將立即添加到套接字緩沖區(qū)中并視為已發(fā)送。返回值的偏移量將始終等于 -1礼华,該方式具有最大的吞吐量咐鹤。
2.3.2 acks=1
當(dāng)leader接受到消息就會(huì)直接給客戶端返回成功,一般情況下這種模式都能很好地保證數(shù)據(jù)的不丟失只有在laeder接受到數(shù)據(jù)圣絮,然后還沒(méi)來(lái)得及同步到follower祈惶,就掛掉了才會(huì)導(dǎo)致數(shù)據(jù)的丟失,這種概率還是比較小的晨雳。這也是默認(rèn)的選擇方式行瑞,兼具較好的吞吐和較高的可靠性奸腺。
2.3.3 acks=-1或者acks=all
當(dāng)leader接受到消息餐禁,并同步到了一定數(shù)量的follower,才向生產(chǎn)者發(fā)生成功的消息,同步到的follower數(shù)量由 broker 端的 min.insync.replicas 決定除非一些不可抗力因素突照,這種方式基本可以確保數(shù)據(jù)完全不丟失帮非。
三、存儲(chǔ)階段
3.1 定義
在這個(gè)階段,消息在Broker端存儲(chǔ)末盔,如果是集群筑舅,消息會(huì)在這個(gè)階段被復(fù)制到其他的副本上。
3.2 說(shuō)明
3.2.1 單節(jié)點(diǎn)
單個(gè)節(jié)點(diǎn)的Broker陨舱,需要配置Broker參數(shù)翠拣,在收到消息后,將消息寫(xiě)入磁盤(pán)后再給Producer 返回確認(rèn)響應(yīng)游盲,這樣即使發(fā)生宕機(jī)误墓,由于消息已經(jīng)被寫(xiě)入磁盤(pán),就不會(huì)丟失消息益缎,恢復(fù)后還可以繼續(xù)消費(fèi)谜慌。
3.2.2 多節(jié)點(diǎn)
Broker是由多個(gè)節(jié)點(diǎn)組成的集群,需要將Broker集群配置成:至少將消息發(fā)送到2個(gè)以上的節(jié)點(diǎn)莺奔,再給客戶端回復(fù)發(fā)送確認(rèn)響應(yīng)欣范。這樣當(dāng)某個(gè)Broker宕機(jī)時(shí),其他的Broker 可以替代宕機(jī)的Broker令哟,也不會(huì)發(fā)生消息丟失恼琼。
四、消費(fèi)階段
消費(fèi)階段采用和生產(chǎn)階段類似的確認(rèn)機(jī)制來(lái)保證消息的可靠傳遞励饵,客戶端從Broker拉取消息后驳癌,執(zhí)行用戶的消費(fèi)業(yè)務(wù)邏輯,成功后役听,才會(huì)給Broker發(fā)送消費(fèi)確認(rèn)響應(yīng)颓鲜。如果Broker沒(méi)有收到消費(fèi)確認(rèn)響應(yīng),下次拉消息的時(shí)候還會(huì)返回同一條消息典予,確保消息不會(huì)在網(wǎng)絡(luò)傳輸過(guò)程中丟失甜滨,也不會(huì)因?yàn)榭蛻舳嗽趫?zhí)行消費(fèi)邏輯中出錯(cuò)導(dǎo)致丟失。
五瘤袖、消息丟失原因
生產(chǎn)者產(chǎn)生消息時(shí)衣摩,由于網(wǎng)絡(luò)原因發(fā)送到 MQ 失敗了、MQ 服務(wù)器持久化捂敌,存儲(chǔ)磁盤(pán)時(shí)出現(xiàn)異常艾扮、Kafka和RocketMQ 的 offset 被回調(diào)時(shí),略過(guò)了很多消息占婉、消費(fèi)者剛讀取消息泡嘴,已經(jīng) ACK 確認(rèn),但業(yè)務(wù)還沒(méi)處理完逆济,服務(wù)就被重啟了酌予。
六磺箕、處理方案
為了解決這個(gè)問(wèn)題,我們可以增加一張消息發(fā)送表抛虫。
1松靡、當(dāng)生產(chǎn)者發(fā)完消息之后,會(huì)往該表中寫(xiě)入一條數(shù)據(jù)(msgId建椰、status)雕欺,狀態(tài) status 標(biāo)記為待確認(rèn)。
2棉姐、如果消費(fèi)者讀取消息之后阅茶,調(diào)用生產(chǎn)者的 API 更新該消息的status為已確認(rèn)。
3谅海、有個(gè)job(xxljob) 每隔一段時(shí)間檢查一次消息發(fā)送表脸哀,如果5分鐘(這個(gè)時(shí)間可以根據(jù)實(shí)際情況來(lái)定)后還有狀態(tài)是待確認(rèn)的消息,則認(rèn)為該消息已經(jīng)丟失了扭吁,重新發(fā)條消息撞蜂。
轉(zhuǎn)載自:MQ怎么保證消息不丟失?