RabbitMQ之面試題總結

1. 消息隊列的作用與使用場景
異步:批量數據異步處理(批量上傳文件)
削峯:高負載任務負載均衡(電商秒殺搶購)
解耦:串行任務並行化(退貨流程解耦)
廣播:基於Pub/Sub實現一對多通信

2. 多個消費者監聽一個隊列時,消息如何分發
輪詢
默認的策略,消費者輪流,平均地接收消息
公平分發
根據消費者的能力來分發消息,給空閒的消費者發送更多消息

//當消費者有x條消息沒有響應ACK時,不再給這個消費者發送消息
	channel.basicQos(int x)

3. 無法被路由的消息去了哪裏
無設置的情況下,無法路由(Routing key錯誤)的消息會被直接丟棄
解決方案:
將mandatory設置爲true,並配合ReturnListener,實現消息的回發

聲明交換機時,指定備份的交換機

 Map<String,Object> arguments = new HashMap<String,Object>();
	arguments.put("alternate-exchange","備份交換機名");

4. 消息在什麼時候會變成死信
消息拒絕並且沒有設置重新入隊
消息過期
消息堆積,並且隊列達到最大長度,先入隊的消息會變成DL

5. RabbitMQ如何實現延時隊列
利用TTL(隊列的消息存活時間或者消息存活時間),加上死信交換機

 // 設置屬性,消息10秒鐘過期
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .expiration("10000") // TTL

 // 指定隊列的死信交換機
        Map<String,Object> arguments = new HashMap<String,Object>();
        arguments.put("x-dead-letter-exchange","DLX_EXCHANGE");

6. 如何保證消息的可靠性投遞
發送方確認模式:
將信道設置成confirm模式(發送方確認模式),則所有在信道上發佈的消息都會被指派一個唯一的ID。
一旦消息被投遞到目的隊列後,或者消息被寫入磁盤後(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一ID)。
如果RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(not acknowledged,未確認)消息。
發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。

接收方確認機制
接收方消息確認機制:消費者接收每一條消息後都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。
這裏並沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
下面羅列幾種特殊情況:
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認爲消息沒有被分發,然後重新分發給下一個訂閱的消費者。(可能存在消息重複消費的隱患,需要去重)
如果消費者接收到消息卻沒有確認消息,連接也未斷開,則RabbitMQ認爲該消費者繁忙,將不會給該消費者分發更多的消息。

7. 消息冪等性
生產者方面:可以對每條消息生成一個msgID,以控制消息重複投遞

 AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
	porperties.messageId(String.valueOF(UUID.randomUUID()))

消費者方面:消息體中必須攜帶一個業務ID,如銀行流水號,消費者可以根據業務ID去重,避免重複消費

8. 消息如何被優先消費

//生產者
 Map<String, Object> argss = new HashMap<String, Object>();
        argss.put("x-max-priority",10);

//消費者
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .priority(5) // 優先級,默認爲5,配合隊列的 x-max-priority 屬性使用

9. 如何保證消息的順序性
一個隊列只有一個消費者的情況下才能保證順序,否則只能通過全局ID實現(每條消息都一個msgId,關聯的消息擁有一個parentMsgId。可以在消費端實現前一條消息未消費,不處理下一條消息;也可以在生產端實現前一條消息未處理完畢,不發佈下一條消息)

10. RabbitMQ的集羣模式和集羣節點類型
**普通模式:**默認模式,以兩個節點(rabbit01,rabbit02)爲例來進行說明,對於Queue來說,消息實體只存在於其中一個節點rabbit01(或者rabbit02),rabbit01和rabbit02兩個節點僅有相同的元數據,即隊列結構。當消息進入rabbit01節點的Queue後,consumer從rabbit02節點消費時,RabbitMQ會臨時在rabbit01,rabbit02間進行消息傳輸,把A中的消息實體取出並經過B發送給consumer,所以consumer應儘量連接每一個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點建立物理Queue。否則無論consumer連rabbit01或rabbit02,出口總在rabbit01,會產生瓶頸。當rabbit01節點故障後,rabbit02節點無法取到rabbit01節點中還未消費的消息實體。如果做了消息持久化,那麼等到rabbit01節點恢復,然後纔可被消費。如果沒有消息持久化,就會產生消息丟失的現象。

**鏡像模式:**把需要的隊列做成鏡像隊列,存在與多個節點屬於RabibitMQ的HA方案,該模式解決了普通模式中的問題,其實質和普通模式不同之處在於,消息體會主動在鏡像節點間同步,而不是在客戶端取數據時臨時拉取,該模式帶來的副作用也很明顯,除了降低系統性能外,如果鏡像隊列數量過多,加之大量的消息進入,集羣內部的網絡帶寬將會被這種同步通訊大大消耗掉,所以在對可靠性要求比較高的場合中適用

節點分爲內存節點(保存狀態到內存,但持久化的隊列和消息還是會保存到磁盤),磁盤節點(保存狀態到內存和磁盤),一個集羣中至少需要一個磁盤節點

11.如何自動刪除長時間沒有消費的消息

// 通過隊列屬性設置消息過期時間
        Map<String, Object> argss = new HashMap<String, Object>();
        argss.put("x-message-ttl",6000);

 // 對每條消息設置過期時間
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .expiration("10000") // TTL

12.消息基於什麼傳輸
RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制

13.如何確保消息不丟失
消息持久化,當然前提是隊列必須持久化
RabbitMQ確保持久性消息能從服務器重啓中恢復的方式是,將它們寫入磁盤上的一個持久化日誌文件,當發佈一條持久性消息到持久交換器上時,Rabbit會在消息提交到日誌文件後才發送響應。
一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ會在持久化日誌中把這條消息標記爲等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啓,那麼Rabbit會自動重建交換器和隊列(以及綁定),並重新發布持久化日誌文件中的消息到合適的隊列。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章