天天看點

RabbitMQ概念

使用RabbitMQ有什麼好處

  • 服務間高度解耦
  • 異步通信性能高
  • 流量削峰

RabbitMQ 中的 broker 是指什麼?cluster 又是指什麼?

  • broker 是指一個或多個 erlang node 的邏輯分組,且 node 上運作着 RabbitMQ 應用程式
  • cluster 是在 broker 的基礎之上,增加了 node 之間共享中繼資料的限制

RabbitMQ 概念裡的 channel、exchange 和 queue 是邏輯概念,還是對應着程序實體?分别起什麼作用?

  • Queue 具有自己的 erlang 程序
  • exchange 内部實作為儲存 binding 關系的查找表
  • channel 是實際進行路由工作的實體(即負責按照routing_key将message投遞給queue),channel是真實 TCP 連接配接之上的虛拟連接配接

vhost 是什麼?起什麼作用?

  • vhost可以了解為虛拟broker
  • vhost可以作為不同權限隔離的手段(vhost範圍的使用者控制)

消息基于什麼傳輸?

  • 使用信道的方式來傳輸資料(建立在真實的TCP連接配接内的虛拟連接配接,且每條TCP連接配接上的信道數量沒有限制)

消息如何分發?

  • 消息以循環(round-robin)的方式發送給可正常處理消息并确認的消費者

消息怎麼路由?

  • 生産者把消息釋出到交換器上
  • 綁定決定了消息如何從路由器路由到特定的隊列
  • 消息最終到達隊列,并被消費者接收

什麼是中繼資料?中繼資料分為哪些類型?包括哪些内容?與 cluster 相關的中繼資料有哪些?中繼資料是如何儲存的?中繼資料在 cluster 中是如何分布的?

  • 在非cluster模式下,中繼資料主要分為

    Queue中繼資料(queue 名字和屬性等)、

    Exchange中繼資料(exchange 名字、類型和屬性等)、

    Binding 中繼資料(存放路由關系的查找表)、

    Vhost中繼資料(vhost 範圍内針對前三者的名字空間限制和安全屬性設定)。

  • 在 cluster 模式下,還包括 cluster 中 node 位置資訊和 node 關系資訊。

    中繼資料按照 erlang node 的類型确定是僅儲存于 RAM 中,還是同時儲存在 RAM 和 disk 上。

    中繼資料在 cluster 中是全 node 分布的。

在單 node 系統和多 node 構成的 cluster 系統中聲明 queue、exchange ,以及進行 binding 會有什麼不同?

  • 單node上聲明queue時,隻要該node上相關中繼資料進行了變更,你就會得到 Queue.Declare-ok 回應;
  • 而在 cluster 上聲明 queue,則要求 cluster上的全部 node 都要進行中繼資料成功更新,才會得到 Queue.Declare-ok 回應。
  • 若 node 類型為 RAM node 則變更的資料僅儲存在記憶體中,若類型為 disk node 則還要變更儲存在磁盤上的資料

cluster 中 node 的失效會對 consumer 産生什麼影響?若是在 cluster 中建立了mirrored queue ,這時 node 失效會對 consumer 産生什麼影響?

  • 若是consumer所連接配接的那個node失效(無論該node是否為consumer所訂閱queue的owner node),則consumer會在發現TCP連接配接斷開時,按标準行為執行重連邏輯,

    并根據“Assume Nothing”原則重建相應的 fabric 即可。

  • 若是失效的node為consumer訂閱queue的owner node,則consumer隻能通過Consumer Cancellation Notification 機制來檢測與該 queue 訂閱關系的終止,否則會出現傻等卻沒有任何消息來到的問題。

若 cluster 中擁有某個 queue 的 owner node 失效了,且該 queue 被聲明具有durable 屬性,是否能夠成功從其他 node 上重新聲明該 queue ?

不能

  • 在這種情況下将得到404NOT_FOUND錯誤。隻能等queue所屬的node恢複後才能使用該queue。

    但若該 queue 本身不具有 durable 屬性,則可在其他 node 上重新聲明。

如何確定消息正确地發送至RabbitMQ?

  • 使用發送方确認模式,確定消息正确地發送到RabbitMQ

如何確定消息接收方消費了消息?

  • 接收方消息确認機制

如何避免消息重複投遞或重複消費?

  • 在消息生産時,MQ内部針對每條生産者發送的消息生成一個inner-msg-id,作為去重和幂等的依據(消息投遞失敗并重傳),避免重複的消息進入隊列;
  • 在消息消費時,要求消息體中必須要有一個bizId(對于同一業務全局唯一,如支付ID、訂單ID、文章ID等)作為去重和幂等的依據,避免同一條消息被重複消費。

如何解決丢資料的問題? 生産者丢資料 消息隊列丢資料 消費者丢資料

  • 生産者丢資料:transaction和confirm模式
  • 消息隊列丢資料:開啟持久化磁盤的配置(和confirm機制配合使用),叢集未全部挂掉的情況還可以引入鏡像隊列
  • 消費者丢資料:啟用手動确認模式

死信隊列和延遲隊列的使用

  • 死信消息:消息被拒絕(Basic.Reject或Basic.Nack)并且設定requeue參數的值為false,消息過期了,隊列達到最大的長度
  • 過期消息:隊列設定過期時間,消息設定過期時間
  • 延時隊列:在rabbitmq中不存在延時隊列(我們可以通過設定消息的過期時間和死信隊列來模拟出延時隊列)消費者監聽死信交換器綁定的隊列,而不要監聽消息發送的隊列

使用:訂單系統中,建立訂單,使用者逾時未支付,取消訂單

使用了消息隊列會有什麼缺點?

  • 系統可用性降低(消息隊列挂掉)
  • 系統複雜性增加(消息一緻性問題,消息重複消費問題,消息可靠傳輸)

RabbitMQ 上的一個 queue 中存放的 message 是否有數量限制?

  • 預設情況下一般是無限制,因為限制取決于機器的記憶體,但是消息過多會導緻處理效率的下降。
  • 同時可以通過參數來限制:

    x-max-length :對隊列中消息的條數進行限制 ,

    x-max-length-bytes :對隊列中消息的總量進行限制。

能夠在地理上分開的不同資料中心使用 RabbitMQ cluster 麼?

不能。

  • 第一,你無法控制所建立的 queue 實際分布在 cluster 裡的哪個 node 上(一般使用 HAProxy + cluster 模型時都是這樣),這可能會導緻各種跨地域通路時的常見問題;
  • 第二,Erlang 的 OTP 通信架構對延遲的容忍度有限,這可能會觸發各種逾時,導緻業務疲于處理;
  • 第三,廣域網上的連接配接失效問題。

為什麼 heavy RPC 的使用場景下不建議采用 disk node ?

  • heavy RPC 是指在業務邏輯中高頻調用 RabbitMQ 提供的 RPC 機制,導緻不斷建立、銷毀 reply queue,進而造成 disk node 的性能問題(因為會針對中繼資料不斷寫盤)。
  • 是以在使用RPC機制時需要考慮自身的業務場景。

RabbitMQ 允許發送的 message 最大可達多大?

  • 消息體的大小由 64-bit 的值來指定

什麼情況下 producer 不主動建立 queue 是安全的?

  • message 是允許丢失的
  • 實作了針對未處理消息的 republish 功能(例如采用Publisher Confirm 機制)

為什麼說保證 message 被可靠持久化的條件是 queue 和 exchange 具有durable 屬性,同時 message 具有 persistent 屬性才行?

  • binding 關系可以表示為 exchange – binding – queue 。
  • 若要求投遞的 message 能夠不丢失,要求 message 本身設定 persistent 屬性,要求 exchange和 queue 都設定 durable 屬性。
  • 若 exchange 或 queue 未設定durable 屬性,則在其 crash 之後就會無法恢複,那麼即使 message 設定了 persistent 屬性,仍然存在 message 雖然能恢複但卻無處容身的問題
  • 同理,若 message 本身未設定persistent 屬性,則 message 的持久化更無從談起

什麼情況下會出現 blackholed 問題?

  • blackholed 問題是指,向 exchange 投遞了 message ,而由于各種原因導緻該message 丢失,但發送者卻不知道。
  • 可導緻 blackholed 的情況:

    1.向未綁定 queue 的exchange 發送 message;

    2.exchange 以 binding_key key_A 綁定了 queue queue_A,但向該 exchange 發送 message 使用的 routing_key 卻是 key_B

如何防止出現 blackholed 問題?

  • 通過各種方式保證相關 fabric 的存在
  • 如果在執行 Basic.Publish 時設定 mandatory=true ,則在遇到可能出現 blackholed 情況時,伺服器會通過傳回 Basic.Return 告之目前 message 無法被正确投遞(内含原因 312NO_ROUTE)。

為什麼不應該對所有的 message 都使用持久化機制?

  • 性能下降(寫磁盤)
  • 僅對關鍵消息作持久化處理(根據業務重要程度),且應該保證關鍵消息的量不會導緻性能瓶頸。