序言:
文章內容輸出來源:拉勾教育Java高薪訓練營。
本篇文章是學習課程中的一部分課后筆記
一、RabbitMQ介紹、概念、基本架構
1. RabbitMQ介紹
RabbitMQ,俗稱“兔子MQ”(可見其輕巧,敏捷),是目前非常熱門的一款開源消息中間件,不管是互聯網行業還是傳統行業都廣泛使用(最早是為了解決電信行業系統之間的可靠通信而設計)。
- 高可靠性、易擴展、高可用、功能豐富等
- 支持大多數(甚至冷門)的編程語言客戶端。
- RabbitMQ遵循AMQP協議,自身采用Erlang(一種由愛立信開發的通用面向并發編程的語言)編寫。
- RabbitMQ也支持MQTT等其他協議。
2. RabbitMQ整體邏輯架構
3. RabbitMQ Exchange類型 :
- RabbitMQ常用的交換器類型有: fanout 、 direct 、 topic 、 headers 四種。
fanout
會把所有發送到該交換器的消息路由到所有與該交換器綁定的隊列中.
direct
把消息路由到那些BindingKey和RoutingKey完全匹配的隊列中
topic
topic類型的交換器在direct匹配規則上進行了擴展,也是將消息路由到BindingKey和RoutingKey相匹配的隊列中,這里的匹配規則稍微不同,它約定:
BindingKey和RoutingKey一樣都是由"."分隔的字符串;
BindingKey中可以存在兩種特殊字符“”和“#”,用于模糊匹配,其中""用于匹配一個單詞,"#"用于匹配多個單詞(可以是0個)。
headers
headers類型的交換器不依賴于路由鍵的匹配規則來路由信息,而是根據發送的消息內容中的headers屬性進行匹配。
在綁定隊列和交換器時指定一組鍵值對,當發送的消息到交換器時,RabbitMQ會獲取到該消息的headers,對比其中的鍵值對是否完全匹配隊列和交換器綁定時指定的鍵值對,如果匹配,消息就會路由到該隊列。headers類型的交換器性能很差,不實用。
4.RabbitMQ數據存儲
RabbitMQ消息有兩種類型:
持久化消息和非持久化消息(這兩種消息都會被寫入磁盤)
- 持久化消息在到達隊列時寫入磁盤,同時會內存中保存一份備份,當內存吃緊時,消息從內存中清除。這會提高一定的性能。
- 非持久化消息一般只存于內存中,當內存壓力大時數據刷盤處理,以節省內存空間。
5.持久化存儲機制
持久化是提高RabbitMQ可靠性的基礎,否則當RabbitMQ遇到異常時(如:重啟、斷電、停機等)數據將會丟失。主要從以下幾個方面來保障消息的持久性:
- Exchange的持久化。通過定義時設置durable 參數為ture來保證Exchange相關的元數據不不丟失。
- Queue的持久化。也是通過定義時設置durable 參數為ture來保證Queue相關的元數據不不丟失。
- 消息的持久化。通過將消息的投遞模式 (BasicProperties 中的 deliveryMode 屬性)設置為 2 即可實現消息的持久化,保證消息自身不丟失。
隊列索引:
索引維護隊列的落盤消息的信息,如存儲地點、是否已被給消費者接收、是否已被消費者ack等。每個隊列都有相對應的索引。
消息存儲:
消息以鍵值對的形式存儲到文件中,一個虛擬主機上的所有隊列使用同一塊存儲,每個節點只有一個。存儲分為持久化存儲(msg_store_persistent)和短暫存儲(msg_store_transient)。持久化存儲的內容在broker重啟后不會丟失,短暫存儲的內容在broker重啟后丟失。
二、RabbitMQ工作流程詳解
1.生產者發送消息的流程
- 生產者連接RabbitMQ,建立TCP連接( Connection),開啟信道(Channel)
- 生產者聲明一個Exchange(交換器),并設置相關屬性,比如交換器類型、是否持久化等
- 生產者聲明一個隊列井設置相關屬性,比如是否排他、是否持久化、是否自動刪除等
- 生產者通過 bindingKey (綁定Key)將交換器和隊列綁定( binding )起來
- 生產者發送消息至RabbitMQ Broker,其中包含 routingKey (路由鍵)、交換器等信息
- 相應的交換器根據接收到的 routingKey 查找相匹配的隊列。
- 如果找到,則將從生產者發送過來的消息存入相應的隊列中。
- 如果沒有找到,則根據生產者配置的屬性選擇丟棄還是回退給生產者
- 關閉信道。
- 關閉連接。
2.消費者接收消息的過程
- 消費者連接到RabbitMQ Broker ,建立一個連接(Connection ) ,開啟一個信道(Channel) 。
- 消費者向RabbitMQ Broker 請求消費相應隊列中的消息,可能會設置相應的回調函數, 以及做一些準備工作
- 等待RabbitMQ Broker 回應并投遞相應隊列中的消息, 消費者接收消息。
- 消費者確認( ack) 接收到的消息。
- RabbitMQ 從隊列中刪除相應己經被確認的消息。
- 關閉信道。
- 關閉連接。
三、RabbitMQ特性
1.TTL機制
TTL,Time to Live 的簡稱,即過期時間。
RabbitMQ 可以對消息和隊列兩個維度來設置TTL。
任何消息中間件的容量和堆積能力都是有限的,如果有一些消息總是不被消費掉,那么需要有一種過期的機制來做兜底。
目前有兩種方法可以設置消息的TTL。
- 通過Queue屬性設置,隊列中所有消息都有相同的過期時間。
- 對消息自身進行單獨設置,每條消息的TTL 可以不同。
如果兩種方法一起使用,則消息的TTL 以兩者之間較小數值為準。通常來講,消息在隊列中的生存時間一旦超過設置的TTL 值時,就會變成“死信”(Dead Message),消費者默認就無法再收到該消息。
2.死信隊列
在定義業務隊列時可以考慮指定一個 死信交換機,并綁定一個死信隊列。當消息變成死信時,該消息就會被發送到該死信隊列上,這樣方便我們查看消息失敗的原因。
- DLX,全稱為Dead-Letter-Exchange,死信交換器。消息在一個隊列中變成死信(Dead Letter)之后,被重新發送到一個特殊的交換器(DLX)中,同時,綁定DLX的隊列就稱為“死信隊列”。
以下幾種情況導致消息變為死信:- 消息被拒絕(Basic.Reject/Basic.Nack),并且設置requeue參數為false;
- 消息過期;
- 隊列達到最大長度。
對于RabbitMQ 來說,DLX 是一個非常有用的特性。它可以處理異常情況下,消息不能夠被消費者正確消費(消費者調用了Basic.Nack 或者Basic.Reject)而被置入死信隊列中的情況,后續分析程序可以通過消費這個死信隊列中的內容來分析當時所遇到的異常情況,進而可以改善
和優化系統。
3.延遲隊列
- 延遲消息是指的消息發送出去后并不想立即就被消費,而是需要等(指定的)一段時間后才觸發消費。
例如下面的業務場景:在支付寶上面買電影票,鎖定了一個座位后系統默認會幫你保留15分鐘時間,如果15分鐘后還沒付款那么不好意思系統會自動把座位釋放掉。怎么實現類似的功能呢?
- 可以用定時任務每分鐘掃一次,發現有占座超過15分鐘還沒付款的就釋放掉。但是這樣做很低效,很多時候做的都是些無用功;
- 可以用分布式鎖、分布式緩存的被動過期時間,15分鐘過期后鎖也釋放了,緩存key也不存在了;
- 還可以用延遲隊列,鎖座成功后會發送1條延遲消息,這條消息15分鐘后才會被消費,消費的過程就是檢查這個座位是否已經是“已付款”狀態;
死信實現延遲隊列
- 生產者將消息(msg)和路由鍵(routekey)發送指定的延時交換機(exchange)上
- 延時交換機(exchange)存儲消息等待消息到期根據路由鍵(routekey)找到綁定自己的隊列(queue)并把消息給它
- 隊列(queue)再把消息發送給監聽它的消費者(customer)