與RabbitMQ有關的一些知識

lpe234發表於2022-12-14
工作中用過一段時間的Kafka,不過主要還是RabbitMQ用的多一些。今天主要來講講與RabbitMQ相關的一些知識。一些基本概念,以及實際使用場景及一些注意事項。

1 基本概念

RabbitMQ使用Erlang開發,實現了高階訊息佇列協議(AMQP),同時還支援MQTT、STOMP等。

image.png

1.1 核心概念

  • Broker: 訊息佇列服務主機
  • Exchange: 訊息交換機,可按照特定規則將訊息路由到具體佇列 (上圖X即為交換機)
  • Queue: 訊息佇列,每個訊息理論都要被投入到一個或多個佇列 (上圖紅色矩形即為佇列)
  • Binding: 繫結關係,將ExchangeQueue按照某個路由規則進行繫結
  • RoutingKey: 路由關鍵字,Exchange根據該Key進行不同的路由
  • Vhost: 虛擬主機,在同一物理主機上做資源邏輯隔離,類似名稱空間?
  • Connection: 客戶端與主機建立的TCP連線
  • Channel: 訊息通道,同一Connection可以有多個Channel,每個Channel都有一個唯一ID

1.2 交換機

按型別分四種:Direct Exchange,Topic Exchage,Fanout Exchange,Headers Exchange

1.2.1 Direct Exchange

直接交換機,在沒複雜路由場景時,這種路由器使用的較多。特點是嚴格RoutingKey路由。只有當RoutingKey完全一致時,才會今天路由投遞。

image.png

1.2.2 Fanout Exchange

廣播交換機,一個訊息需要無差別投遞到所有繫結的佇列中時。無需設定RoutingKey,即使設定了也不會生效。

image.png

1.2.3 Topic Exchange

主題交換機,類似直接交換機。不同的是可以根據RoutingKey進行模糊匹配(#表示一個或多個單詞,*表示一個單詞)。

這樣來看的話。

  • 當不使用#*進行模糊匹配時,它跟Direct Exchange似乎沒啥區別。
  • 當僅使用#進行模糊匹配時,它跟Fanout Exchange似乎也沒啥區別。

image.png

可以看到:

  • Q1可以匹配:x11.orange.x22,但無法匹配x00.x11.orange.x22
  • Q2可以匹配:lazy.orange,也能匹配lazy.orange.rabbit
1.2.4 Headers Exchange

請求頭交換機,不使用RoutingKey路由,根據訊息頭中的key-value屬性進行路由。

image.png

可以透過設定x-match: anyx-match: all來進行orand邏輯匹配。

1.2.5 其他屬性
  • Durability: Durable(持久的),Transiant(短暫的)。
  • Auto delete:當有佇列或交換機繫結了本交換機,在佇列或者交換機都又進行了解綁後,自動刪除
  • Internal: 是否為內部使用。true 表示為內部交換機,客戶端無法直接向該交換機傳送訊息。
  • Arguments:

    • alternate-exchange: 備份交換機,當訊息無法路由到具體佇列時,將交給備份交換機處理。

1.3 佇列

訊息只能存在於佇列中,下面看一下佇列都有哪些屬性。

  • Type: Classic,Quorum
  • Durability: Durable(持久的),Transiant(短暫的)
  • Auto delete: 當有消費者訂閱,然後所有的消費者又都斷開連線,則自動刪除
  • Arguments:

    • x-message-ttl: MessageQueue中存活時間,超時將被丟棄
    • x-expires: Queue在沒有被使用的情況下,過期時間
    • x-max-length: Queue中可以存放的最大訊息數,超過將被丟棄
    • x-max-length-bytes: Queue中可以存放最大訊息體大小,超過將被丟棄
    • x-overflow: Queue溢位後的行為,drop-headreject-publishreject-publish-dlx
    • x-single-active-consumer: 確保只有一個消費者訂閱,當出現異常時自動轉向另外一個。
    • x-max-priority: 佇列支援的最大優先順序,不設定將不支援。
    • x-dead-letter-exchange: 當Messagerejectedexpire時,將會被重新發布到哪個交換機。
    • x-dead-letter-routing-key: 當成為死信時,使用的RoutingKey,未設定時則使用原始Key
    • x-queue-mode: 當設定為lazy時,會將訊息儘可能的放置到磁碟上,以減少記憶體使用。
    • x-queue-master-locator: 將佇列設定為主節點定位模式。

2 使用場景

應用場景一般為三類: 非同步、解耦、削峰填谷。

2.1 非同步

非同步一般是指: 同一個系統內,使用佇列將請求和響應非同步化,不阻塞主執行緒,從而獲得更高的處理速度,以提升系統效能。

最早在做商城專案時。使用者下單付款後先更新本地訂單記錄,然後再向第三方物流系統推送待發貨訊息、向使用者發放訂單相關站內信、並可能觸發積分贈送及推薦人的返利計算、以及可能觸發相關營銷規則發放優惠券等操作。

image.png

2.2 解耦

解耦一般指: 不同系統間,透過佇列方式進行通訊,使系統間不至於過度依賴,減少系統間耦合性。

在最近的專案中,有做的一個事件上報系統,其實就是各個系統都接入。每個系統即可做生產者、也可以做消費者。比如使用者在下單後,需要給推薦人贈送積分、向外部CRM同步商機已成單狀態等。

image.png

2.3 削峰填谷

削峰填谷一般指: 利用佇列作為緩衝,將短時大流量快取起來,由消費者來決定處理速度。使得系統負載趨於平穩,從而提高系統穩定性。

在做使用者增長業務相關,使用者由落地頁提交資料至內部系統,內部系統會將資料簡單處理後推送到外部CRM系統,銷售在跟客戶溝通後,會將線索轉換為商機。在這個轉換過程中,會由CRM向內部系統推送資料。內部系統會根據傳遞過來的資料進行各種操作,如建立、更新家長,建立、更新學生,以及各種附加業務資訊等。

image.png

3 常見問題

3.1 訊息重複問題

訊息重複的場景很多,比如系統出錯、呼叫超時重試機制、訊息消費異常時ReQueue操作等情況。很多時候為了保證訊息的可靠傳遞,會保證訊息at-least-once。這種情況下基本無法保證不重複傳送,所以消費端要保證冪等性。

既然提到重複性,必然要有重複的依據。比如訂單號,同一系統內不允許重複。

  • 可藉助資料庫的唯一索引,也可藉助Redis來保證資料唯一。
  • 如果沒有重複依據,只能大概根據引數值按一定規則做雜湊處理,不過這種可能存在誤判和漏判問題。

3.2 訊息堆積

消費堆積,無非就是消費速度趕不上生產速度。產生的原因有很多,消費者異常出現消費變慢問題、生產者突發大流量等情況。

解決方案要同時考慮生產者和消費者。發生堆積時,將部分生產者降級,關閉非核心業務,減少訊息產生。消費者最佳化效能,將堆積訊息臨時轉移至新佇列,啟用新的消費者去消費。

3.3 訊息丟失問題

從整個流程考慮,生產者、佇列、消費者三方面。

  • 生產者: 保證訊息成功推送到佇列。
  • 佇列: 保證已推送到佇列中的資料不會丟失。
  • 消費者: 保證已消費的資料被正確處理。

4 後記

系統設計沒有銀彈。在引入一箇中介軟體時,要綜合考慮、權衡利弊。引入中介軟體,能解決一些問題,但可能會帶來更多的問題。

做好系統監控,像消費堆積有些場景下是可預知的,比如臨時做活動或者低價促銷之類造成的訂單激增。而有些像系統故障類,無法提前預知,則需要監控系統做到及時告警,提前介入處理。


echo '5Y6f5Yib5paH56ugOiDmjpjph5Eo5L2g5oCO5LmI5Zad5aW26Iy25ZWKWzkyMzI0NTQ5NzU1NTA4MF0pL+aAneWQpihscGUyMzQp' | base64 -d

相關文章