前言
往期專題
2020互聯網Java後端面試必備解析—Redis23題面試
2020互聯網Java後端面試必備解析—JVM21題算法
面試還不懂這10道Spring問題,回去等通知了後端
2020互聯網Java後端面試必備解析—SpringCloud20題安全
學習導圖
來分享一下面試必備的RabbitMQ問題解析!用XMind畫了一張導圖記錄RabbitMQ的學習筆記和一些面試解析(源文件對部分節點有詳細備註和參考資料,歡迎關注個人公衆號:阿風的架構筆記 後臺發送【導圖】拿下載連接,已經完善更新):服務器

一、上千萬條消息在mq中積壓了幾個小時還沒解決:
- 先修復consumer的問題,確保其恢復消費速度,而後將現有consumer都停掉;
- 新建⼀個topic,partition是原來的10倍,臨時建⽴好原先10倍或者20倍的queue數量;
- 而後寫⼀個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據;消費以後不作耗時的處理,直接均勻輪詢寫⼊臨時建⽴好的10倍數量的queue;
- 接着臨時徵⽤10倍的機器來部署consumer,每⼀批consumer消費⼀個臨時queue的數據;
- 這種作法至關因而臨時將queue資源和consumer資源擴⼤10倍,以正常的10倍速度來消費數據;
- 等快速消費完積壓數據以後,得恢復原先部署架構,從新⽤原先的consumer機器來消費消息。
總結:markdown
- 修復並停掉consumer;
- 新建⼀個topic,partition是原來的10倍,建⽴臨時queue,數量是原來的10倍或20倍;
- 寫臨時consumer程序,臨時徵⽤10倍的機器去消費數據;
- 消費完成以後,恢復原先consumer;
二、rabbitmq設置過時時間,部分消息丟失:
採起批量重導⽅法:將丟失的那批數據查詢導⼊到mq⾥⾯。架構
三、RabbitMQ 上的⼀個 queue 中存放的 message 是否有數量限制?
能夠認爲是⽆限制,由於限制取決於機器的內存,可是消息過多會致使處理效率的降低。併發
四、分佈式部署:
RabbitMQ⽆法容忍不一樣數據中⼼之間⽹絡延遲,可是能夠經過3種⽅式實現分佈式部署:Federation和Shovel。 異步
五、如何確保消息正確地發送⾄RabbitMQ?
RabbitMQ使⽤發送⽅確認模式,確保消息正確地發送到RabbitMQ。分佈式
**發送⽅確認模式:**將信道設置成confirm模式(發送⽅確認模式),則全部在信道上發佈的消息
都會被指派⼀個惟⼀的ID。⼀旦消息被投遞到⽬的隊列後,或者消息被寫⼊磁盤後(可持久化
的消息),信道會發送⼀個確認給⽣產者(包含消息惟⼀ID)。若是RabbitMQ發⽣內部錯誤
從⽽致使消息丟失,會發送⼀條nack(not acknowledged,未確認)消息。
發送⽅確認模式是異步的,⽣產者應⽤程序在等待確認的同時,能夠繼續發送消息。當確認消息到達⽣產者應⽤程序,⽣產者應⽤程序的回調⽅法就會被觸發來處理確認消息。
六、如何確保消息接收⽅消費了消息?
**接收⽅消息確認機制:**消費者接收每⼀條消息後都必須進⾏確認(消息接收和消息確認是兩個不一樣操做)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。
這⾥並無⽤到超時機制,RabbitMQ僅經過Consumer的鏈接中斷來確認是否須要從新發送消息。也就是說,只要鏈接不中斷,RabbitMQ給了Consumer⾜夠⻓的時間來處理消息。
特殊狀況:
- 若是消費者接收到消息,在確認以前斷開了鏈接或取消訂閱,RabbitMQ會認爲消息沒有被分發,而後從新分發給下⼀個訂閱的消費者。(可能存在消息重複消費的隱患,須要根據bizId去重)
- 若是消費者接收到消息卻沒有確認消息,鏈接也未斷開,則RabbitMQ認爲該消費者繁忙,將不會給該消費者分發更多的消息。
七、如何避免消息重複投遞或重複消費?
在消息⽣產時,MQ內部針對每條⽣產者發送的消息⽣成⼀個inner-msg-id,做爲去重和冪等的依據(消息投遞失敗並重傳),避免重複的消息進⼊隊列;在消息消費時,要求消息體中必需要有⼀個bizId(對於同⼀業務全局惟⼀,如⽀付ID、訂單ID、帖⼦ID等)做爲去重和冪等的依據,避免同⼀條消息被重複消費。
八、消息基於什麼傳輸?
因爲TCP鏈接的建立和銷燬開銷較⼤,且併發數受系統資源限制,會形成性能瓶頸。
RabbitMQ使⽤信道的⽅式來傳輸數據。信道是建⽴在真實的TCP鏈接內的虛擬鏈接,且每條
TCP鏈接上的信道數量沒有限制。
- RabbitMQ採⽤相似NIO(Non-blocking I/O)作法,選擇TCP鏈接復⽤,不只能夠減小性能開銷,同時也便於管理。
- 每一個線程把持⼀個信道,因此信道服⽤了Connection的TCP鏈接。同時RabbitMQ能夠確保每一個線程的私密性,就像擁有獨⽴的鏈接⼀樣。
九、消息如何分發?
若該隊列⾄少有⼀個消費者訂閱,消息將以循環(round-robin)的⽅式發送給消費者。每條消息只會分發給⼀個訂閱的消費者(前提是消費者可以正常處理消息並進⾏確認)。
十、消息怎麼路由?
**從概念上來講,消息路由必須有三部分:**交換器、路由、綁定。⽣產者把消息發佈到交換器上;綁定決定了消息如何從交換器路由到特定的隊列;消息最終到達隊列,並被消費者接收。
- 消息發佈到交換器時,消息將擁有⼀個路由鍵(routing key),在消息建立時設定。
- 經過隊列路由鍵,能夠把隊列綁定到交換器上。
- 消息到達交換器後,RabbitMQ會將消息的路由鍵與隊列的路由鍵進⾏匹配(針對不一樣的交換器有不一樣的路由規則)。
- 若是可以匹配到隊列,則消息會投遞到相應隊列中;若是不能匹配到任何隊列,消息將進⼊ 「⿊洞」。
十一、如何確保消息不丟失?
消息持久化的前提是:將交換器/隊列的durable屬性設置爲true,表示交換器/隊列是持久交換器/隊列,在服務器崩潰或重啓以後不須要從新建立交換器/隊列(交換器/隊列會⾃動建立)。
若是消息想要從Rabbit崩潰中恢復,那麼消息必須:
- 在消息發佈前,經過把它的 「投遞模式」 選項設置爲2(持久)來把消息標記成持久化
- 將消息發送到持久交換器
- 消息到達持久隊列
RabbitMQ確保持久性消息能從服務器重啓中恢復的⽅式是,將它們寫⼊磁盤上的⼀個持久化⽇志⽂件,當發佈⼀條持久性消息到持久交換器上時,Rabbit會在消息提交到⽇志⽂件後才發送響應(若是消息路由到了⾮持久隊列,它會⾃動從持久化⽇志中移除)。⼀旦消費者從持久隊列中消費了⼀條持久化消息,RabbitMQ會在持久化⽇志中把這條消息標記爲等待垃圾收集。若是持久化消息在被消費以前RabbitMQ重啓,那麼Rabbit會⾃動重建交換器和隊列(以及綁定),並重播持久化⽇志⽂件中的消息到合適的隊列或者交換器上。
十二、使⽤RabbitMQ有什麼好處?
- 應⽤解耦(系統拆分)
- 異步處理(預定掛號業務處理成功後,異步發送短信、推送消息、⽇志記錄等,能夠⼤⼤減⼩響應時間)
- 消息分發
- **流量削峯:**將請求發送到隊列中,短暫的⾼峯期積壓是容許的。
- 消息緩衝
1三、消息隊列有什麼缺點?
- **系統可⽤性下降:**消息隊列出問題影響業務;
- **系統複雜性增長:**加⼊消息隊列,須要考慮不少⽅⾯的問題,⽐如:⼀致性問題、如何保證消息不被重複消費、如何保證消息可靠性傳輸等。
1四、MQ如何選型?

- 中⼩型公司⾸選RabbitMQ:管理界⾯簡單,⾼併發。
- ⼤型公司能夠選擇RocketMQ:更⾼併發,可對rocketmq進⾏定製化開發。
- ⽇志採集功能,⾸選kafka,專爲⼤數據準備。
1五、如何保證消息隊列⾼可⽤?
1. 集羣:

- 集羣能夠擴展消息通訊的吞吐量,可是不會備份消息,備份消息要經過鏡像隊列的⽅式解決。
- 隊列存儲在單個節點、交換器存儲在全部節點。
**2. 鏡像隊列:**將須要消費的隊列變爲鏡像隊列,存在於多個節點,這樣就能夠實現RabbitMQ
的HA⾼可⽤性。做⽤就是消息實體會主動在鏡像節點之間實現同步,⽽不是像普通模式那樣,
在consumer消費數據時臨時讀取。缺點就是,集羣內部的同步通信會佔⽤⼤量的⽹絡帶寬。

1六、如何保證消息的順序性?
- 經過某種算法,將須要保持前後順序的消息放到同⼀個消息隊列中(kafka中就是partition,rabbitMq中就是queue)。而後只⽤⼀個消費者去消費該隊列。
- 能夠在消息體內添加全局有序標識來實現。
1七、使用RabbitMQ增長rest服務吞吐量。

1八、RabbitMQ交換器有哪些類型?
- **fanout交換器:**它會把全部發送到該交換器的消息路由到全部與該交換器綁定的隊列中;
- **direct交換器:**direct類型的交換器路由規則很簡單,它會把消息路由到哪些BindingKey和RoutingKey徹底匹配的隊列中;
- **topic交換器:**匹配規則⽐direct更靈活。
- **headers交換器:**根據發送消息內容的headers屬性進⾏匹配(因爲性能不好,不實⽤)
常⽤的交換器主要分爲如下三種:
- **direct:**若是路由鍵徹底匹配,消息就被投遞到相應的隊列
- **fanout:**若是交換器收到消息,將會⼴播到全部綁定的隊列上
- **topic:**可使來⾃不一樣源頭的消息可以到達同⼀個隊列。 使⽤topic交換器時,可使⽤通配符,⽐如:「*」 匹配特定位置的任意⽂本, 「.」 把路由鍵分爲了⼏部分,「#」 匹配全部規則等。特別注意:發往topic交換器的消息不能隨意的設置選擇鍵(routing_key),必須是由"."隔開的⼀系列的標識符組成
1九、RabbitMQ如何保證數據⼀致性?
- **⽣產者確認機制:**消息持久化後異步回調通知⽣產者,保證消息已經發出去;
- **消息持久化:**設置消息持久化;
- **消費者確認機制:**消費者成功消費消息以後,⼿動確認,保證消息已經消費。
20、RabbitMQ消費者自動擴展數量
SimpleMessageListenerContainer可根據RabbitMQ消息堆積狀況⾃動擴展消費者數量。
2一、RabbitMQ結構:

- Broker:簡單來講就是消息隊列服務器實體。
- Exchange:消息交換機,它指定消息按什麼規則,路由到哪一個隊列。
- Queue:消息隊列載體,每一個消息都會被投⼊到⼀個或多個隊列。
- Binding:綁定,它的做⽤就是把exchange和queue按照路由規則綁定起來。
- Routing Key:路由關鍵字,exchange根據這個關鍵字進⾏消息投遞。
- vhost:虛擬主機,⼀個broker⾥能夠開設多個vhost,⽤做不一樣⽤戶的權限分離。
- producer:消息⽣產者,就是投遞消息的程序。
- consumer:消息消費者,就是接受消息的程序。
- channel:消息通道,在客戶端的每一個鏈接⾥,可建⽴多個channel,每一個channel表明⼀個會話任務。
2二、rabbitmq隊列與消費者的關係?
- ⼀個隊列能夠綁定多個消費者;
- 消息默認以循環的⽅式發送給消費者;
- 消費者收到消息默認⾃動確認,也能夠改爲⼿動確認。
彩蛋
歡迎你們關注個人公衆號【阿風的架構筆記】,2020年面試必備的Java後端進階面試題總結了一些學習文檔筆記和麪試解析,共2000頁,文章都會在裏面更新,整理的資料回覆【2020】領取!
