4. MQ消息的可靠性&處理消息丟失

一 分析

數(shù)據(jù)的丟失問題镰绎,可能出現(xiàn)在生產者狗唉、MQ摊册、消費者中罢缸,咱們從 RabbitMQ 和 Kafka 分別來分析一下吧校读。

二 RabbitMQ

rabbitmq-message-lose

2.1 RabbitMQ生產者弄丟了數(shù)據(jù)

生產者將數(shù)據(jù)發(fā)送到 RabbitMQ 的時候,可能數(shù)據(jù)就在半路給搞丟了祖能,因為網絡問題啥的歉秫,都有可能。RabbitMQ針對生產者丟失數(shù)據(jù)可以有兩種方案解決問題:

  • Plan-A : 此時可以選擇用 RabbitMQ 提供的事務功能养铸,就是生產者發(fā)送數(shù)據(jù)之前開啟 RabbitMQ 事務channel.txSelect雁芙,然后發(fā)送消息,如果消息沒有成功被 RabbitMQ 接收到钞螟,那么生產者會收到異常報錯兔甘,此時就可以回滾事務channel.txRollback,然后重試發(fā)送消息鳞滨;如果收到了消息洞焙,那么可以提交事務channel.txCommit
// 開啟事務
channel.txSelect
try {
    // 這里發(fā)送消息
} catch (Exception e) {
    channel.txRollback

    // 這里再次重發(fā)這條消息
}

// 提交事務
channel.txCommit
  • Plan-A的缺陷: :RabbitMQ 事務機制(同步)一搞拯啦,基本上吞吐量會下來澡匪,因為太耗性能
  • Plan-B : 要確保說寫 RabbitMQ 的消息別丟褒链,可以開啟 confirm 模式唁情,在生產者那里設置開啟 confirm 模式之后,你每次寫的消息都會分配一個唯一的 id甫匹,然后如果寫入了 RabbitMQ 中甸鸟,RabbitMQ 會給你回傳一個 ack 消息,告訴你說這個消息 ok 了兵迅。如果 RabbitMQ 沒能處理這個消息抢韭,會回調你的一個 nack 接口,告訴你這個消息接收失敗恍箭,你可以重試刻恭。而且你可以結合這個機制自己在內存里維護每個消息 id 的狀態(tài),如果超過一定時間還沒接收到這個消息的回調季惯,那么你可以重發(fā)吠各。

RabbitMQ 事務機制與confirm 機制

  • 事務機制和 confirm 機制最大的不同在于,事務機制是同步的勉抓,你提交一個事務之后會阻塞在那兒贾漏,但是 confirm 機制是異步的,你發(fā)送個消息之后就可以發(fā)送下一個消息藕筋,然后那個消息 RabbitMQ 接收了之后會異步回調你的一個接口通知你這個消息接收到了纵散。

  • 所以一般在生產者這塊避免數(shù)據(jù)丟失,都是用 confirm 機制的。

2.2 RabbitMQ 弄丟了數(shù)據(jù)

RabbitMQ 自己弄丟了數(shù)據(jù)伍掀,這個你必須開啟 RabbitMQ 的持久化掰茶,就是消息寫入之后會持久化到磁盤,哪怕是 RabbitMQ 自己掛了蜜笤,恢復之后會自動讀取之前存儲的數(shù)據(jù)濒蒋,一般數(shù)據(jù)不會丟。除非極其罕見的是把兔,RabbitMQ 還沒持久化沪伙,自己就掛了,可能導致少量數(shù)據(jù)丟失县好,但是這個概率較小围橡。
設置持久化有兩個步驟

  • 創(chuàng)建 queue 的時候將其設置為持久化
    這樣就可以保證 RabbitMQ 持久化 queue 的元數(shù)據(jù),但是它是不會持久化 queue 里的數(shù)據(jù)的缕贡。
  • 第二個是發(fā)送消息的時候將消息的 deliveryMode 設置為 2
    就是將消息設置為持久化的翁授,此時 RabbitMQ 就會將消息持久化到磁盤上去。

必須要同時設置這兩個持久化才行晾咪,RabbitMQ 哪怕是掛了收擦,再次重啟,也會從磁盤上重啟恢復 queue禀酱,恢復這個 queue 里的數(shù)據(jù)炬守。

注意,哪怕是你給 RabbitMQ 開啟了持久化機制剂跟,也有一種可能,就是這個消息寫到了 RabbitMQ 中酣藻,但是還沒來得及持久化到磁盤上曹洽,結果不巧,此時 RabbitMQ 掛了辽剧,就會導致內存里的一點點數(shù)據(jù)丟失送淆。

所以,持久化可以跟生產者那邊的 confirm 機制配合起來怕轿,只有消息被持久化到磁盤之后偷崩,才會通知生產者 ack 了,所以哪怕是在持久化到磁盤之前撞羽,RabbitMQ 掛了阐斜,數(shù)據(jù)丟了,生產者收不到 ack诀紊,你也是可以自己重發(fā)的谒出。

2.3 RabbitMQ消費端弄丟了數(shù)據(jù)

消費者丟失了數(shù)據(jù),主要是因為消費的時候,剛消費到笤喳,還沒處理为居,結果進程掛了,比如重啟了杀狡,那么就尷尬了蒙畴,RabbitMQ 認為你都消費了,這數(shù)據(jù)就丟了呜象。

這個時候得用 RabbitMQ 提供的 ack 機制忍抽,簡單來說,就是你必須關閉 RabbitMQ 的自動 ack董朝,可以通過一個 api 來調用就行鸠项,然后每次你自己代碼里確保處理完的時候,再在程序里 ack 一把子姜。這樣的話祟绊,如果你還沒處理完,不就沒有 ack 了哥捕?那 RabbitMQ 就認為你還沒處理完牧抽,這個時候 RabbitMQ 會把這個消費分配給別的 consumer 去處理,消息是不會丟的遥赚。

2.4 總結

RabbitMQ 消息丟失及對應解決方案:

  • 生產者丟失:
    • 方案1:開啟RabbitMQ事務機制(同步扬舒,影響性能,不推薦)凫佛。
    • 方案2:開啟RabbitMQ confirm機制(異步讲坎,推薦)
  • RabbitMQ本身丟失:
    • 開啟RabbitMQ持久化機制。
    • 配合生產者那邊的confirm機制保證小時持久化后才進行ack.
  • 消費者丟失:
    • 關閉RabbitMQ自動ACK機制愧薛,在程序顯示調用API進行確認晨炕。

三 Kafka

3.1 Kafka消費端弄丟了數(shù)據(jù)

  • 唯一可能導致消費者弄丟數(shù)據(jù)的情況,就是說毫炉,你消費到了這個消息瓮栗,然后消費者那邊自動提交了 offset,讓 Kafka 以為你已經消費好了這個消息瞄勾,但其實你才剛準備處理這個消息费奸,你還沒處理,你自己就掛了进陡,此時這條消息就丟咯愿阐。
  • Kafka 會自動提交 offset,那么只要關閉自動提交 offset四濒,在處理完之后自己手動提交 offset换况,就可以保證數(shù)據(jù)不會丟职辨。但是此時確實還是可能會有重復消費,比如你剛處理完戈二,還沒提交 offset舒裤,結果自己掛了,此時肯定會重復消費一次觉吭,自己保證冪等性就好了腾供。

3.2 Kafka 弄丟了數(shù)據(jù)

這塊比較常見的一個場景,就是 Kafka 某個 broker 宕機鲜滩,然后重新選舉 partition 的 leader伴鳖。大家想想,要是此時其他的 follower 剛好還有些數(shù)據(jù)沒有同步徙硅,結果此時 leader 掛了榜聂,然后選舉某個 follower 成 leader 之后,不就少了一些數(shù)據(jù)嗓蘑?這就丟了一些數(shù)據(jù)啊须肆。

所以此時一般是要求起碼設置如下 4 個參數(shù):

  • 給 topic 設置 replication.factor 參數(shù):這個值必須大于 1,要求每個 partition 必須有至少 2 個副本桩皿。
  • 在 Kafka 服務端設置 min.insync.replicas 參數(shù):這個值必須大于 1豌汇,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯(lián)系,沒掉隊泄隔,這樣才能確保 leader 掛了還有一個 follower 吧拒贱。
  • 在 producer 端設置 acks=all:這個是要求每條數(shù)據(jù),必須是寫入所有 replica 之后佛嬉,才能認為是寫成功了逻澳。
  • 在 producer 端設置 retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗巷燥,就無限重試赡盘,卡在這里了。

我們生產環(huán)境就是按照上述要求配置的缰揪,這樣配置之后,至少在 Kafka broker 端就可以保證在 leader 所在 broker 發(fā)生故障葱淳,進行 leader 切換時钝腺,數(shù)據(jù)不會丟失。

3.3 生產者會不會弄丟數(shù)據(jù)

如果按照上述的思路設置了 acks=all赞厕,一定不會丟艳狐,要求是,你的 leader 接收到消息皿桑,所有的 follower 都同步到了消息之后毫目,才認為本次寫成功了蔬啡。如果沒滿足這個條件,生產者會自動不斷的重試镀虐,重試無限次箱蟆。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刮便,隨后出現(xiàn)的幾起案子空猜,更是在濱河造成了極大的恐慌,老刑警劉巖恨旱,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辈毯,死亡現(xiàn)場離奇詭異,居然都是意外死亡搜贤,警方通過查閱死者的電腦和手機谆沃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仪芒,“玉大人唁影,你說我怎么就攤上這事∽懒颍” “怎么了夭咬?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铆隘。 經常有香客問我卓舵,道長,這世上最難降的妖魔是什么膀钠? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任掏湾,我火速辦了婚禮,結果婚禮上肿嘲,老公的妹妹穿的比我還像新娘融击。我一直安慰自己,他們只是感情好雳窟,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布尊浪。 她就那樣靜靜地躺著,像睡著了一般封救。 火紅的嫁衣襯著肌膚如雪拇涤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天誉结,我揣著相機與錄音鹅士,去河邊找鬼。 笑死惩坑,一個胖子當著我的面吹牛掉盅,可吹牛的內容都是我干的也拜。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼趾痘,長吁一口氣:“原來是場噩夢啊……” “哼慢哈!你這毒婦竟也來了?” 一聲冷哼從身側響起扼脐,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤岸军,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瓦侮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艰赞,經...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年肚吏,在試婚紗的時候發(fā)現(xiàn)自己被綠了方妖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡罚攀,死狀恐怖党觅,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情斋泄,我是刑警寧澤杯瞻,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站炫掐,受9級特大地震影響魁莉,放射性物質發(fā)生泄漏。R本人自食惡果不足惜募胃,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一旗唁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痹束,春花似錦检疫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至论巍,卻和暖如春剿牺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背环壤。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钞诡,地道東北人郑现。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓湃崩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親接箫。 傳聞我的和親對象是個殘疾皇子攒读,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內容