前言
來分享一下面試必備的RabbitMQ問題解析! 用XMind畫了一張導圖記錄RabbitMQ的學習筆記和一些面試解析(源文件對部分節點有詳細備註和參考資料,已經完善更新):
1、上千萬條消息在mq中積壓了幾個小時還沒解決:
- 先修復consumer的問題,確保其恢復消費速度,然後將現有consumer都停掉;
- 新建⼀個topic,partition是原來的10倍,臨時建⽴好原先10倍或者20倍的queue數量;
- 然後寫⼀個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據;消費之後不做耗時的處理,直接均勻輪詢寫⼊臨時建⽴好的10倍數量的queue;
- 接著臨時徵⽤10倍的機器來部署consumer,每⼀批consumer消費⼀個臨時queue的數據;
- 這種做法相當於是臨時將queue資源和consumer資源擴⼤10倍,以正常的10倍速度來消費數據;
- 等快速消費完積壓數據之後,得恢復原先部署架構,重新⽤原先的consumer機器來消費消息。
總結:
- 修復並停掉consumer;
- 新建⼀個topic,partition是原來的10倍,建⽴臨時queue,數量是原來的10倍或20倍;
- 寫臨時consumer程序,臨時徵⽤10倍的機器去消費數據;
- 消費完成之後,恢復原先consumer;
2、rabbitmq設置過期時間,部分消息丟失:
採取批量重導⽅法:將丟失的那批數據查詢導⼊到mq⾥⾯。
3、RabbitMQ 上的⼀個 queue 中存放的 message 是否有數量限制?
可以認為是⽆限制,因為限制取決於機器的內存,但是消息過多會導致處理效率的下降。
4、分佈式部署:
RabbitMQ⽆法容忍不同數據中⼼之間⽹絡延遲,但是可以通過3種⽅式實現分佈式部署:Federation和Shovel。
5、如何確保消息正確地發送⾄RabbitMQ?
RabbitMQ使⽤發送⽅確認模式,確保消息正確地發送到RabbitMQ。
發送⽅確認模式:將信道設置成confirm模式(發送⽅確認模式),則所有在信道上發佈的消息
都會被指派⼀個唯⼀的ID。⼀旦消息被投遞到⽬的隊列後,或者消息被寫⼊磁盤後(可持久化
的消息),信道會發送⼀個確認給⽣產者(包含消息唯⼀ID)。如果RabbitMQ發⽣內部錯誤
從⽽導致消息丟失,會發送⼀條nack(not acknowledged,未確認)消息。
發送⽅確認模式是異步的,⽣產者應⽤程序在等待確認的同時,可以繼續發送消息。當確認消息到達⽣產者應⽤程序,⽣產者應⽤程序的回調⽅法就會被觸發來處理確認消息。
6、如何確保消息接收⽅消費了消息?
接收⽅消息確認機制:消費者接收每一條消息後都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。
這⾥並沒有⽤到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer⾜夠⻓的時間來處理消息。
特殊情況:
- 如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然後重新分發給下一個訂閱的消費者。(可能存在消息重複消費的隱患,需要根據bizId去重)
- 如果消費者接收到消息卻沒有確認消息,連接也未斷開,則RabbitMQ認為該消費者繁忙,將不會給該消費者分發更多的消息。
7、如何避免消息重複投遞或重複消費?
在消息⽣產時,MQ內部針對每條⽣產者發送的消息⽣成⼀個inner-msg-id,作為去重和冪等的依據(消息投遞失敗並重傳),避免重複的消息進⼊隊列;在消息消費時,要求消息體中必須要有⼀個bizId(對於同⼀業務全局唯⼀,如⽀付ID、訂單ID、帖⼦ID等)作為去重和冪等的依據,避免同⼀條消息被重複消費。
8、消息基於什麼傳輸?
由於TCP連接的創建和銷燬開銷較⼤,且併發數受系統資源限制,會造成性能瓶頸。
RabbitMQ使⽤信道的⽅式來傳輸數據。信道是建⽴在真實的TCP連接內的虛擬連接,且每條
TCP連接上的信道數量沒有限制。
- RabbitMQ採⽤類似NIO(Non-blocking I/O)做法,選擇TCP連接復⽤,不僅可以減少性能開銷,同時也便於管理。
- 每個線程把持⼀個信道,所以信道服⽤了Connection的TCP連接。同時RabbitMQ可以確保每個線程的私密性,就像擁有獨立的連接一樣。
9、消息如何分發?
若該隊列⾄少有⼀個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給⼀個訂閱的消費者(前提是消費者能夠正常處理消息並進行確認)。
10、消息怎麼路由?
從概念上來說,消息路由必須有三部分:交換器、路由、綁定。⽣產者把消息發佈到交換器上;綁定決定了消息如何從交換器路由到特定的隊列;消息最終到達隊列,並被消費者接收。
- 消息發佈到交換器時,消息將擁有⼀個路由鍵(routing key),在消息創建時設定。
- 通過隊列路由鍵,可以把隊列綁定到交換器上。
- 消息到達交換器後,RabbitMQ會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規則)。
- 如果能夠匹配到隊列,則消息會投遞到相應隊列中;如果不能匹配到任何隊列,消息將進⼊ “⿊洞”。
11、如何確保消息不丟失?
消息持久化的前提是:將交換器/隊列的durable屬性設置為true,表示交換器/隊列是持久交換器/隊列,在服務器崩潰或重啟之後不需要重新創建交換器/隊列(交換器/隊列會⾃動創建)。
如果消息想要從Rabbit崩潰中恢復,那麼消息必須:
- 在消息發佈前,通過把它的 “投遞模式” 選項設置為2(持久)來把消息標記成持久化
- 將消息發送到持久交換器
- 消息到達持久隊列
RabbitMQ確保持久性消息能從服務器重啟中恢復的⽅式是,將它們寫⼊磁盤上的⼀個持久化⽇志⽂件,當發佈⼀條持久性消息到持久交換器上時,Rabbit會在消息提交到⽇志⽂件後才發送響應(如果消息路由到了⾮持久隊列,它會⾃動從持久化⽇志中移除)。⼀旦消費者從持久隊列中消費了⼀條持久化消息,RabbitMQ會在持久化⽇志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啟,那麼Rabbit會⾃動重建交換器和隊列(以及綁定),並重播持久化⽇志⽂件中的消息到合適的隊列或者交換器上。
12、使⽤RabbitMQ有什麼好處?
- 應⽤解耦(系統拆分)
- 異步處理(預約掛號業務處理成功後,異步發送短信、推送消息、⽇志記錄等,可以⼤⼤減⼩響應時間)
- 消息分發
- 流量削峰:將請求發送到隊列中,短暫的⾼峰期積壓是允許的。
- 消息緩衝
13、消息隊列有什麼缺點?
- 系統可⽤性降低:消息隊列出問題影響業務;
- 系統複雜性增加:加⼊消息隊列,需要考慮很多⽅⾯的問題,⽐如:⼀致性問題、如何保證消息不被重複消費、如何保證消息可靠性傳輸等。
14、MQ如何選型?
- 中⼩型公司⾸選RabbitMQ:管理界⾯簡單,⾼併發。
- ⼤型公司可以選擇RocketMQ:更⾼併發,可對rocketmq進⾏定製化開發。
- ⽇志採集功能,⾸選kafka,專為⼤數據準備。
15、如何保證消息隊列⾼可⽤?
1. 集群:
- 集群可以擴展消息通信的吞吐量,但是不會備份消息,備份消息要通過鏡像隊列的⽅式解決。
- 隊列存儲在單個節點、交換器存儲在所有節點。
2. 鏡像隊列:將需要消費的隊列變為鏡像隊列,存在於多個節點,這樣就可以實現RabbitMQ
的HA⾼可⽤性。作⽤就是消息實體會主動在鏡像節點之間實現同步,⽽不是像普通模式那樣,
在consumer消費數據時臨時讀取。缺點就是,集群內部的同步通訊會佔⽤⼤量的⽹絡帶寬。
16、如何保證消息的順序性?
- 通過某種算法,將需要保持先後順序的消息放到同⼀個消息隊列中(kafka中就是partition,rabbitMq中就是queue)。然後只⽤⼀個消費者去消費該隊列。
- 可以在消息體內添加全局有序標識來實現。
17、使用RabbitMQ增加rest服務吞吐量。
18、RabbitMQ交換器有哪些類型?
- fanout交換器:它會把所有發送到該交換器的消息路由到所有與該交換器綁定的隊列中;
- direct交換器:direct類型的交換器路由規則很簡單,它會把消息路由到哪些BindingKey和RoutingKey完全匹配的隊列中;
- topic交換器:匹配規則⽐direct更靈活。
- headers交換器:根據發送消息內容的headers屬性進⾏匹配(由於性能很差,不實⽤)
常⽤的交換器主要分為以下三種:
- direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
- fanout:如果交換器收到消息,將會⼴播到所有綁定的隊列上
- topic:可以使來⾃不同源頭的消息能夠到達同⼀個隊列。 使⽤topic交換器時,可以使⽤通配符,⽐如:“*” 匹配特定位置的任意⽂本, “.” 把路由鍵分為了⼏部分,“#” 匹配所有規則等。特別注意:發往topic交換器的消息不能隨意的設置選擇鍵(routing_key),必須是由"."隔開的⼀系列的標識符組成
19、RabbitMQ如何保證數據⼀致性?
- ⽣產者確認機制:消息持久化後異步回調通知⽣產者,保證消息已經發出去;
- 消息持久化:設置消息持久化;
- 消費者確認機制:消費者成功消費消息之後,⼿動確認,保證消息已經消費。
20、RabbitMQ消費者自動擴展數量
SimpleMessageListenerContainer可根據RabbitMQ消息堆積情況⾃動擴展消費者數量。
21、RabbitMQ結構:
- Broker:簡單來說就是消息隊列服務器實體。
- Exchange:消息交換機,它指定消息按什麼規則,路由到哪個隊列。
- Queue:消息隊列載體,每個消息都會被投⼊到⼀個或多個隊列。
- Binding:綁定,它的作⽤就是把exchange和queue按照路由規則綁定起來。
- Routing Key:路由關鍵字,exchange根據這個關鍵字進⾏消息投遞。
- vhost:虛擬主機,⼀個broker⾥可以開設多個vhost,⽤作不同⽤戶的權限分離。
- producer:消息⽣產者,就是投遞消息的程序。
- consumer:消息消費者,就是接受消息的程序。
- channel:消息通道,在客戶端的每個連接⾥,可建⽴多個channel,每個channel代表⼀個會話任務。
22、rabbitmq隊列與消費者的關係?
- ⼀個隊列可以綁定多個消費者;
- 消息默認以循環的⽅式發送給消費者;
- 消費者收到消息默認⾃動確認,也可以改成⼿動確認。
彩蛋
2020年面試必備的Java後端進階面試題總結了一些學習文檔筆記和麵試解析,共2000頁,有需要的朋友麻煩轉發後關注
私信回覆【面試】獲取資料免費領取方式吧!閱讀更多 Java清風 的文章