RabbitMQ

一、什么是 RabbitMQ?

RabbitMQ 是實現(xiàn)了高級消息隊列協(xié)議(AMQP)的開源消息代理軟件(亦稱面向消息的中間件),最大的特點就是消費并不需要確保提供方存在,實現(xiàn)了服務(wù)之間的高度解耦。RabbitMQ 服務(wù)器是用 Erlang 語言編寫的,而集群和故障轉(zhuǎn)移是構(gòu)建在開放電信平臺框架上的。所有主要的編程語言均有與代理接口通訊的客戶端庫。

重要的角色

  1. 生產(chǎn)者:消息的創(chuàng)建者,負責(zé)創(chuàng)建和推送數(shù)據(jù)到消息服務(wù)器。
  2. 消費者:消息的接收方,用于處理數(shù)據(jù)和確認消息。
  3. 代理:就是 RabbitMQ 本身,用于扮演“快遞”的角色,本身不生產(chǎn)消息,只是扮演“快遞”的角色。

重要的組件

  1. ConnectionFactory(連接管理器):應(yīng)用程序與 RabbitMQ 之間建立連接的管理器,程序中使用。
  2. Channel(信道):消息推送使用的通道。
  3. Exchange(交換器):用于接受、分配消息。
  4. Queue(隊列):用于存儲生產(chǎn)者的消息。
  5. RoutingKey(路由鍵):用于把生成者的數(shù)據(jù)分配到交換器上。
  6. BindingKey(綁定鍵):用于把交換器的消息綁定到隊列上。

二、為什么要使用 RabbitMQ

  1. 在分布式系統(tǒng)下具備異步、削峰、負載均衡等一系列高級功能。異步通信性能高。
  2. 擁有持久化的機制,進程消息,隊列中的信息也可以保存下來。
  3. 實現(xiàn)消費者和生產(chǎn)者之間的解耦。
  4. 高并發(fā)場景下,利用消息隊列可以使得同步訪問變?yōu)榇性L問達到一定量的限流,利于數(shù)據(jù)庫的操作。
  5. 可以使用消息隊列達到異步下單的效果,排隊中,后臺進行邏輯下單。

三、RabbitMQ 的使用場景

  1. 【流量削峰】搶購活動,削峰填谷,防止系統(tǒng)崩塌。
  2. 【定時任務(wù)】延遲信息處理,比如 10 分鐘之后給下單未付款的用戶發(fā)送郵件提醒。
  3. 【解耦、服務(wù)間異步通信】對于新增的功能可以單獨寫模塊擴展,比如用戶確認評價之后,新增了給用戶返積分的功能,此時不用在業(yè)務(wù)代碼里添加新增積分的功能,只需要把新增積分的接口訂閱確認評價的消息隊列即可,后面再添加任何功能只需要訂閱對應(yīng)的消息隊列即可。
  4. 順序消費。實現(xiàn)原理:同一隊列中保持有序;相同業(yè)務(wù)的 ID 分配到相同的隊列。

四、如何確保消息正確地發(fā)送至 RabbitMQ?如何確保消息接收方消費了消息?

1??發(fā)送方確認模式
將信道設(shè)置成 confirm 模式(發(fā)送方確認模式),則所有在信道上發(fā)布的消息都會被指派一個唯一的 ID。一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發(fā)送一個確認給生產(chǎn)者(包含消息唯一 ID)。如果 RabbitMQ 發(fā)生內(nèi)部錯誤從而導(dǎo)致消息丟失,會發(fā)送一條 nack(notacknowledged,未確認)消息。發(fā)送方確認模式是異步的,生產(chǎn)者應(yīng)用程序在等待確認的同時,可以繼續(xù)發(fā)送消息。當確認消息到達生產(chǎn)者應(yīng)用程序,生產(chǎn)者應(yīng)用程序的回調(diào)方法就會被觸發(fā)來處理確認消息。

2??接收方確認機制
消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ 才能安全地把消息從隊列中刪除。這里并沒有用到超時機制,RabbitMQ 僅通過 Consumer 的連接中斷來確認是否需要重新發(fā)送消息。也就是說,只要連接不中斷,RabbitMQ 給了 Consumer 足夠長的時間來處理消息。保證數(shù)據(jù)的最終一致性。

3??下面羅列幾種特殊情況:
①如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ 會認為消息沒有被分發(fā),然后重新分發(fā)給下一個訂閱的消費者。(可能存在消息重復(fù)消費的隱患,需要去重)
②如果消費者接收到消息卻沒有確認消息,連接也未斷開,則 RabbitMQ 認為該消費者繁忙,將不會給該消費者分發(fā)更多的消息。

消息的可靠性怎么是保證的

①生產(chǎn)者端:通過同步發(fā)送消息,收到服務(wù)端的確認寫入并存儲,來保證一致性;RabbitMQ 還支持先寫入本地磁盤再發(fā)送給服務(wù)端
②服務(wù)器端:通過把消息寫入磁盤、數(shù)據(jù)庫、分布式存儲系統(tǒng)中,保證服務(wù)端的可靠性。
③消費端:通過消費端確認消費成功,才進行下一條消費;通過消息重試保證最終會被消費。

五、如何避免消息重復(fù)投遞或重復(fù)消費?

MQ 的服務(wù)端通常不保證消息不重復(fù),由業(yè)務(wù)端來去重。主要是消費端業(yè)務(wù)邏輯保持冪等性;也可以由消息的服務(wù)端通過 messageId 保證,但是通常不這么做。在消息生產(chǎn)時,MQ 內(nèi)部針對每條生產(chǎn)者發(fā)送的消息生成一個 inner-msg-id,作為去重的依據(jù)(消息投遞失敗并重傳),避免重復(fù)的消息進入隊列;在消息消費時,要求消息體中必須要有一個 bizId (對于同一業(yè)務(wù)全局唯一,如支付 ID、訂單 ID 等)作為去重的依據(jù),避免同一條消息被重復(fù)消費。

消息重復(fù)消費的場景

  1. 網(wǎng)絡(luò)出現(xiàn)抖動。
  2. 消費端任務(wù)執(zhí)行超時。
  3. 消費端出現(xiàn)異常。

業(yè)務(wù)端如何保證冪等性

  1. 使用唯一字段,建立唯一性索引。
  2. 多版本控制。
  3. 狀態(tài)機冪等。
  4. 保證數(shù)據(jù)唯一性的其它方式,比如通過 redis、zk 等方式。

六、RabbitMQ 的消息是怎么發(fā)送的?

由于 TCP 連接的創(chuàng)建和銷毀開銷較大,且并發(fā)數(shù)受系統(tǒng)資源限制,會造成性能瓶頸。RabbitMQ 使用信道的方式來傳輸數(shù)據(jù)。信道是建立在真實的 TCP 連接內(nèi)的虛擬連接,且每條 TCP 連接上的信道數(shù)量沒有限制。

首先客戶端必須連接到 RabbitMQ 服務(wù)器才能發(fā)布和消費消息,客戶端和 rabbit server 之間會創(chuàng)建一個 TCP 連接,一旦 TCP 打開并通過了認證(認證就是你發(fā)送給 rabbit 服務(wù)器的用戶名和密碼),你的客戶端和 RabbitMQ 就創(chuàng)建了一條 amqp 信道(channel),信道是創(chuàng)建在“真實” TCP 上的虛擬連接,amqp 命令都是通過信道發(fā)送出去的,每個信道都會有一個唯一的 id,不論是發(fā)布消息,訂閱隊列都是通過這個信道完成的。若該隊列至少有一個消費者訂閱,消息將以循環(huán)(round-robin)的方式發(fā)送給消費者。每條消息只會分發(fā)給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行確認)。通過路由可實現(xiàn)多消費的功能。

七、消息怎么路由?

消息提供方--->路由--->一至多個隊列。消息發(fā)布到交換器時,消息將擁有一個路由鍵(routing key),在消息創(chuàng)建時設(shè)定。通過隊列路由鍵,可以把隊列綁定到交換器上。消息到達交換器后,RabbitMQ 會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規(guī)則)。

常用的交換器(廣播類型)主要分為以下四種:

  1. direct(默認):最基礎(chǔ)最簡單的模式,發(fā)送方把消息發(fā)送給訂閱方,如果有多個訂閱者,默認采取輪詢的方式進行消息發(fā)送。如果路由鍵完全匹配,消息就被投遞到相應(yīng)的隊列。
  2. headers:與 direct 類似,只是性能很差,此類型幾乎用不到。
  3. fanout:分發(fā)模式,把消費分發(fā)給所有訂閱者。如果交換器收到消息,將會廣播到所有綁定的隊列上。
  4. topic:匹配訂閱模式,使用正則匹配到消息隊列,能匹配到的都能接收到??梢允箒碜圆煌搭^的消息能夠到達同一個隊列。 使用 topic 交換器時,可以使用通配符。

八、RabbitMQ 怎么避免消息丟失

消息持久化,當然前提是隊列必須持久化。RabbitMQ 確保持久性消息能從服務(wù)器重啟中恢復(fù)的方式是,將它們寫入磁盤上的一個持久化日志文件,當發(fā)布一條持久性消息到持久交換器上時,RabbitMQ 會在消息提交到日志文件后才發(fā)送響應(yīng)。一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ 會在持久化日志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前 RabbitMQ 重啟,那么 RabbitMQ 會自動重建交換器和隊列(以及綁定),并重新發(fā)布持久化日志文件中的消息到合適的隊列。每個集群中至少有一個物理磁盤,保證消息落入磁盤。

九、RabbitMQ 持久化的缺點

持久化的缺點就是降低了服務(wù)器的吞吐量,因為使用的是磁盤而非內(nèi)存存儲,從而降低了吞吐量??杀M量使用 ssd 硬盤來緩解吞吐量的問題。

十、要保證消息持久化成功的條件有哪些?

  1. 聲明隊列必須設(shè)置持久化 durable 設(shè)置為 true.
  2. 消息推送投遞模式必須設(shè)置持久化,deliveryMode 設(shè)置為 2(持久)。
  3. 消息已經(jīng)到達持久化交換器。
  4. 消息已經(jīng)到達持久化隊列。

以上四個條件都滿足才能保證消息持久化成功。

十一、RabbitMQ 節(jié)點的類型

  1. 磁盤節(jié)點:消息會存儲到磁盤。
  2. 內(nèi)存節(jié)點:消息都存儲在內(nèi)存中,重啟服務(wù)器消息丟失,性能高于磁盤類型。

十二、RabbitMQ 集群中唯一的磁盤節(jié)點崩潰了會怎樣

如果唯一磁盤的磁盤節(jié)點崩潰了,不能進行以下操作:

  1. 不能創(chuàng)建隊列
  2. 不能創(chuàng)建交換器
  3. 不能創(chuàng)建綁定
  4. 不能添加用戶
  5. 不能更改權(quán)限
  6. 不能添加和刪除集群節(jié)點

唯一磁盤節(jié)點崩潰了,集群是可以保持運行的,但不能更改任何東西。

十三、RabbitMQ 為什么每個節(jié)點不是其他節(jié)點的完整拷貝

  1. 存儲空間的考慮:如果每個節(jié)點都擁有所有隊列的完全拷貝,這樣新增節(jié)點不但沒有新增存儲空間,反而增加了更多的冗余數(shù)據(jù)。
  2. 性能的考慮:如果每條消息都需要完整拷貝到每一個集群節(jié)點,那新增節(jié)點并沒有提升處理消息的能力,最多是保持和單節(jié)點相同的性能甚至是更糟。

十四、RabbitMQ 的集群鏡像集群模式

無論元數(shù)據(jù)還是 queue 里的消息都會存在于多個實例上,然后每次寫消息到 queue 的時候,都會自動到多個實例的 queue 里進行消息同步。

好處在于:任何一個機器宕機了,別的機器都可以用。
壞處在于:①性能開銷太大,消息同步所有機器,導(dǎo)致網(wǎng)絡(luò)帶寬壓力和消耗很重。②沒有擴展性可言,如果某個 queue 負載很重,加機器,新增的機器也包含了這個 queue 的所有數(shù)據(jù),并沒有辦法線性擴展 queue。

十五、RabbitMQ 集群有什么用?

集群主要有以下兩個用途:
高可用:某個服務(wù)器出現(xiàn)問題,整個 RabbitMQ 還可以繼續(xù)使用;
高容量:集群可以承載更多的消息量。

十六、RabbitMQ 集群搭建需要注意哪些問題?

各節(jié)點之間使用“–link”連接,此屬性不能忽略。
各節(jié)點使用的 erlang cookie 值必須相同,此值相當于“秘鑰”的功能,用于各節(jié)點的認證。
整個集群中必須包含一個磁盤節(jié)點。

十七、RabbitMQ 對集群節(jié)點停止順序有要求嗎?

RabbitMQ 對集群的停止的順序是有要求的,應(yīng)該先關(guān)閉內(nèi)存節(jié)點,最后再關(guān)閉磁盤節(jié)點。如果順序恰好相反的話,可能會造成消息的丟失。

十八、RabbitMQ 中 vhost 的作用是什么?

每個 RabbitMQ 都能創(chuàng)建很多 vhost,稱之為虛擬主機,每個虛擬主機其實都是 mini 版的RabbitMQ,它擁有自己的隊列,交換器和綁定,擁有自己的權(quán)限機制。

十九、RabbitMQ 實現(xiàn)延遲消息隊列的兩種方式

  1. 通過消息過期后進入死信交換器,再由交換器轉(zhuǎn)發(fā)到延遲消費隊列,實現(xiàn)延遲功能。
  2. 使用 RabbitMQ-delayed-message-exchange 插件實現(xiàn)延遲功能。

二十、消息隊列消息推拉模式是什么意思,分別在什么場景下適用

①推:服務(wù)端主動;拉:消費端主動。
②看消費端的消費能力,處理復(fù)雜時間長的適合拉模式,推模式實時性響應(yīng)更好;其中推對于消費端要求更高,拉對于 MQ 服務(wù)端的堆積能力要求較高。

二十一、假設(shè)發(fā)送一條消息需要 2ms,如何用最短時間完成300條消息的發(fā)送

創(chuàng)建多個 producter,然后使用一個線程池進行分組發(fā)送。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容