rabbitMQ 消息丟問題以及詳情

消息中間件的作用

工作中經常用到消息中間件來解決系統間的解耦問題或者高併發消峯問題,但是消息的可靠性如何保證一直是個很大的問題,萬一消息丟了怎麼辦?什麼情況下消息就不見了呢?下面通過這篇文章,我們就聊聊RabbitMQ 中消息的可靠性如何解決的?

rabbitMQ的消息傳遞過程

在這裏插入圖片描述

rabbitMQ的丟失場景

1.生產者生產消息到RabbitMQ Server 消息丟失場景

  • 1) 外界環境問題導致:

    發生網絡丟包、網絡故障等造成RabbitMQ Server端收不到消息,因爲生產環境的網絡是很複雜的,網絡抖動,丟包現象很常見,下面會講到針對這個問題是如何解決的。

  • 2) 代碼層面,配置層面,考慮不全導致消息丟失

    事例1: 一般情況下,生產者使用Confirm模式投遞消息,如果方案不夠嚴謹,比如RabbitMQ Server
    接收消息失敗後會發送nack消息通知生產者,生產者監聽消息失敗或者沒做任何事情,消息存在丟失風險;

    事例2:
    生產者發送消息到exchange後,發送的路由和queue沒有綁定,消息會存在丟失情況,下面會講到具體的例子,保證意外情況的發生,即使發生,也在可控範圍內。

2.RabbitMQ Server中存儲的消息丟失或可靠性不足

  • 1)消息未完全持久化,當機器重啓後,消息會全部丟失,甚至Queue也不見了

    假如:你僅僅持久化了Message,而Exchange,Queue沒有持久化,這個持久化是無效的。
    記得之前公司有一哥們忘記持久化Queue導致機器重啓後,Queue不見了,自然Message也丟失了。

  • 2)單節點模式問題,如果某個節點掛了,消息就不能用了,業務可能癱瘓,只能等待

    如果做了消息持久化方案,消息會持久化硬盤,機器重啓後消息不會丟失;但是還有一個極端情況,這臺服務器磁盤突然壞了(公司遇到過磁盤問題還是很多的),消息持久化不了,非高可用狀態,這個模式生產環境慎重考慮。

  • 3)普通集羣模式:某個節點掛了,該節點上的消息不能用,有影響的業務癱瘓,只能等待節點恢復重啓可用(建立在消息持久化)

    雖然這個模式進步了一點點,多個節點,但是消息還是不能保證可靠,爲什麼呢?

    因爲RabbitMQ 集羣模式有點特殊,隊列的內容僅僅存在某一個節點上面,不會存在所有節點上面,所有節點僅僅存放消息結構和元數據(可以理解爲索引,這也是爲了提高性能,如果每次把所有內容同步到所有節點是有開銷代價的)。
    在這裏插入圖片描述這裏有三個節點,通常情況下一個磁盤節點,兩個內存節點,首先先說明下, Queue1 內容僅僅存在節點note1上面,在創建隊列的時候已經固定了,note2,note3 僅僅存放的是元數據,這個一定要清楚,Producer發送消息到note2,note2 會同步元數據到其他節點,內容會同步note1。

    那我們想下,圖中的Q1問題,note1掛了,這個節點的Queues全部暫時不可用,節點恢復後可用。

    我們說下圖片中備註2中的問題,Producer發送消息到note2,note2在同步note1前note1掛了,此時你的心情是怎麼樣的。。。後面會講具體的策略

  • 4)鏡像模式:可以解決上面的問題,但是還是有意外情況發生

    比如:持久化的消息,保存到硬盤過程中,當前隊列節點掛了,存儲節點硬盤又壞了,消息丟了,怎麼辦?下面會詳細介紹

3.RabbitMQ Server到消費者消息丟失

消費端接收到相關消息之後,消費端還沒來得及處理消息,消費端機器就宕機了,此時消息如果處理不當會有丟失風險,後面會講到如何處理這個情況,消費端也有ack機制

rabbitMQ 消息丟失機制

如何保證消息不丟失一
如何保證消息不丟失二

1. 生產者生產消息到RabbitMQ Server可靠性保證

這個過程,消息可能會丟,比如發生網絡丟包、網絡故障等造成消息丟失,一般情況下如果不採取措施,生產者無法感知消息是否已經正確無誤的發送到exchange中,如果生產者能感知到的話,它可以進行進一步的處理動作,比如重新投遞相關消息以確保消息的可靠性。

1.1 通常有一種方案可以解決:就是 AMQP協議提供的一個事務機制

RabbitMQ客戶端中Channel 接口提供了幾個事務機制相關的方法:
channel.txSelect :開始事務

channel.txCommit:提交事務

channel.txRollback:回滾事務
不推薦中這樣做,因爲這是同步的,一旦發生阻塞十分影響效率

1.2 幸運的是RabbitMQ提供了一個改進方案,即發送方確認機制(publisher confirm)

首先生產者通過調用channel.confirmSelect方法將信道設置爲confirm模式,一旦信道進入confirm模式,所有在該信道上面發佈的消息都會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之後,RabbitMQ就會發送一個確認(Basic.Ack)給生產者(包含消息的唯一deliveryTag和multiple參數),這就使得生產者知曉消息已經正確到達了目的地了。

其實Confirm模式有三種方式實現:

串行confirm模式:producer每發送一條消息後,調用waitForConfirms()方法,等待broker端confirm,如果服務器端返回false或者在超時時間內未返回,客戶端進行消息重傳。
批量confirm模式:producer每發送一批消息後,調用waitForConfirms()方法,等待broker端confirm。
異步confirm模式:提供一個回調方法,broker confirm了一條或者多條消息後producer端會回調這個方法。
我們分別來看看這三種confirm模式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章