以下內容,部分取材於官方教程,部分來源網絡博主的分享,如有興趣了解更多詳細的知識點,可以在本文最后的文章列表中獲取原地址
RabbitMQ 是一個基於 AMQP 協議實現的企業級消息系統,想要順暢的玩耍的前提是得先了解它,本文將主要介紹 rabbitmq 的一些基本知識點
- 特點
- 基本概念
- 消息投遞消費的幾種姿勢
- 事務
- 集群
I. 基本知識點
它是采用 Erlang 語言實現的 AMQP(Advanced Message Queued Protocol)的消息中間件,最初起源於金融系統,用在分布式系統存儲轉發消息,目前廣泛應用於各類系統用於解耦、削峰
1.特點
首先得了解一下 rabbitmq 的特點,看看是否滿足我們的系統需求(畢竟學習一個框架也是要不少時間的)
以下內容來自: MQ 和 RabbitMQ 作用特點
主要特點,大致可以歸納為以下幾個
- 可靠性:通過支持消息持久化,支持事務,支持消費和傳輸的 ack 等來確保可靠性
- 路由機制:支持主流的訂閱消費模式,如廣播,訂閱,headers 匹配等
- 擴展性:多個 RabbitMQ 節點可以組成一個集群,也可以根據實際業務情況動態地擴展集群中節點。
- 高可用性:隊列可以在集群中的機器上設置鏡像,使得在部分節點出現問題的情況下隊仍然可用。
- 多種協議:RabbitMQ 除了原生支持 AMQP 協議,還支持 STOMP,MQTT 等多種消息中間件協議。
- 多語言客戶端:RabbitMQ 幾乎支持所有常用語言,比如 Jav a、Python、Ruby、PHP、C#、JavaScript 等。
- 管理界面:RabbitMQ 提供了一個易用的用戶界面,使得用戶可以監控和管理消息、集群中的節點等。
- 插件機制:RabbitMQ 提供了許多插件,以實現從多方面進行擴展,當然也可以編寫自己的插件。
2. 基本概念
下圖為 rabbitmq 的內部結構圖
從上圖也可以發現幾個基本概念(Message, Publisher, Exchange, Binding, Queue, Channel, Consuer, Virtual host)
下面逐一進行說明
a. Message
具體的消息,包含消息頭(即附屬的配置信息)和消息體(即消息的實體內容)
由發布者,將消息推送到 Exchange,由消費者從 Queue 中獲取
b. Publisher
消息生產者,負責將消息發布到交換器(Exchange)
c. Exchange
交換器,用來接收生產者發送的消息並將這些消息路由給服務器中的隊列
d. Binding
綁定,用於給 Exchange 和 Queue 建立關系,從而決定將這個交換器中的哪些消息,發送到對應的 Queue
e. Queue
消息隊列,用來保存消息直到發送給消費者
它是消息的容器,也是消息的終點
一個消息可投入一個或多個隊列
消息一直在隊列里面,等待消費者連接到這個隊列將其取走
f. Connection
連接,內部持有一些 channel,用於和 queue 打交道
g. Channel
信道(通道),MQ 與外部打交道都是通過 Channel 來的,發布消息、訂閱隊列還是接收消息,這些動作都是通過 Channel 完成;
簡單來說就是消息通過 Channel 塞進隊列或者流出隊列
h. Consumer
消費者,從消息隊列中獲取消息的主體
i. Virtual Host
虛擬主機,表示一批交換器、消息隊列和相關對象。
虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。
每個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有自己的隊列、交換器、綁定和權限機制。
vhost 是 AMQP 概念的基礎,必須在連接時指定,RabbitMQ 默認的 vhost 是 /
可以理解為 db 中的數據庫的概念,用於邏輯拆分
j. Broker
消息隊列服務器實體
3. 消息投遞消費
從前面的內部結構圖可以知曉,消息由生產者發布到 Exchange,然后通過路由規則,分發到綁定 queue 上,供消費者獲取消息
接下來我們看一下 Exchange 支持的四種策略
a. Direct 策略
消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將消息發到對應的隊列中
簡單來講,就是rounting key
與binding key
完全匹配
- 如果一個隊列綁定到交換機要求路由鍵為
dog
- 只轉發
routing key
標記為dog
的消息, - 不會轉發
dog.puppy
,也不會轉發“dog.guard”等等 - 它是完全匹配、單播的模式
舉例說明
Exchange 和兩個隊列綁定在一起:
- Q1 的 bindingkey 是 orange
- Q2 的 binding key 是 black 和 green.
- 當 Producer 發布一個消息,其
routing key
是orange
時, exchange 會把它放到 Q1 上, 如果是black
或green
就會到 Q2 上, 其余的 Message 被丟棄
注意
- 當有多個隊列綁定到同一個 Exchange,且 binding key 相同時,這時消息會分發給所有滿足條件的隊列
b. Topic 策略
這個策略可以看成是 Direct 策略的升級版,通過routing key
與 bingding key
的模式匹配方式來分發消息
簡單來講,直接策略是完全精確匹配,而 topic 則支持正則匹配,滿足某類指定規則的(如以 xxx 開頭的路由鍵),可以將消息分發過去
#
匹配 0 個或多個單詞*
匹配不多不少一個單詞
一個更直觀的實例如下
Producer 發送消息時需要設置 routing_key,
- Q1 的 binding key 是
*.orange.*
- Q2 是
*.*.rabbit
和lazy.#
: - 發布一個
routing key
為test.orange.mm
消息,則會路由到 Q1;- 注意: 如果是
routng key
是test.orange
則無法路由到 Q1, - 因為 Q1 的規則是三個單詞,中間一個為 orange,不滿足這個規則的都無效
- 注意: 如果是
- 發布一個
routing key
為test.qq.rabbit
或者lazy.qq
的消息 都可以分發到 Q2;即路由 key 為三個單詞,最后一個為 rabbit 或者不限制單詞個數,主要第一個是 lazy 的消息,都可以分發過來 - 如果發布的是一個
test.orange.rabbit
消息,則 Q1 和 Q2 都可以滿足- 注意: 這時兩個隊列都會接受到這個消息
c. Fanout 策略
廣播策略,忽略routing key
和 binding key
,將消息分發給所有綁定在這個 exchange 上的 queue
d. Headers 策略
這個實際上用得不多,它是根據 Message 的一些頭部信息來分發過濾 Message,忽略 routing key 的屬性,如果 Header 信息和 message 消息的頭信息相匹配
II. 消息一致性問題
在進入 rabbitmq 如何保證一致性之前,我們先得理解,什么是消息一致性?
1. 一致性問題
按照我個人的粗淺理解,我認為的消息一致性,應該包含下面幾個
- 生產者,確保消息發布成功
- 消息不會丟
- 順序不會亂
- 消息不會重復(如重傳,導致發布一次,卻出現多個消息)
- 消費者,確保消息消費成功
- 有序消費
- 不重復消費
發送端
為了確保發布者推送的消息不會丟失,我們需要消息持久化
- broker 持久化消息
為了確定消息正確接收
- publisher 需要知道消息投遞並成功持久化
2. 持久化
這里的持久化,主要是指將內存中的消息保存到磁盤,避免 mq 宕機導致的內存中消息丟失;然而單純的持久化,只是保證一致性的其中一個要素,比如 publisher 將消息發送到 exchange,在 broker 持久化的工程中,宕機了導致持久化失敗,而 publisher 並不知道持久化失敗,這個時候就會出現數據丟失,為了解決這個問題,rabbitmq 提供了事務機制
3. 事務機制
事務機制能夠解決生產者與 broker 之間消息確認的問題,只有消息成功被 broker 接受,事務才能提交成功,否則就進行事務回滾操作並進行消息重發。但是使用事務機制會降低 RabbitMQ 的消息吞吐量,不適用於需要發布大量消息的業務場景。
注意,事務是同步的
4. 消息確認機制
消息確認機制,可以區分為生產端和消費端
生產端
- 生產者將信道設置成 Confirm 模式,一旦信道進入 Confirm 模式,所有在該信道上面發布的消息都會被指派一個唯一的 ID(以 confirm.select 為基礎從 1 開始計數),
- 一旦消息被投遞到所有匹配的隊列之后,Broker 就會發送一個確認給生產者(包含消息的唯一 ID),這就使得生產者知道消息已經正確到達目的隊列了,
- 如果消息和隊列是可持久化的,那么確認消息會將消息寫入磁盤之后發出,
- Broker 回傳給生產者的確認消息中 deliver-tag 域包含了確認消息的序列號(此外 Broker 也可以設置 basic.ack 的 multiple 域,表示到這個序列號之前的所有消息都已經得到了處理)
Confirm 模式屬性異步,publisher 發布一條消息之后,在等信道返回確認的同時,依然可以繼續發送下一條消息,所以小概率會出現投遞的消息順序和 broker 中持久化消息順序不一致的問題
一般從編程角度出發,Confirm 模式有三種姿勢
- 普通 Confirm 模式:發送一條消息之后,等到服務器 confirm,然后再發布下一條消息(串行發布)
- 批量 Confirm 模式:發送一批消息之后,等到服務器 confirm,然后再發布下一批消息(如果失敗,這一批消息全部重復,所以會有重復問題)
- 異步 Confirm 模式:提供一個回調方法,服務器 confirm 之后,觸發回調方法,因此不會阻塞下一條消息的發送
消費端
ACK 機制是消費者從 RabbitMQ 收到消息並處理完成后,反饋給 RabbitMQ,RabbitMQ 收到反饋后才將此消息從隊列中刪除。
- 如果一個消費者在處理消息出現了網絡不穩定、服務器異常等現象,那么就不會有 ACK 反饋,RabbitMQ 會認為這個消息沒有正常消費,會將消息重新放入隊列中
- 如果在集群的情況下,RabbitMQ 會立即將這個消息推送給這個在線的其他消費者。這種機制保證了在消費者服務端故障的時候,不丟失任何消息和任務
- 消息永遠不會從 RabbitMQ 中刪除,只有當消費者正確發送 ACK 反饋,RabbitMQ 確認收到后,消息才會從 RabbitMQ 服務器的數據中刪除
III. 集群
按照目前的發展趨勢,一個不支持集群的中間件基本上是不會有市場的;rabbitmq 也是支持集群的,下面簡單的介紹一下常見的 4 種集群架構模式
以下內容來自網上博文,詳情請點擊右邊:RabbitMQ 的 4 種集群架構
1. 主備模式
這個屬於常見的集群模式了,但又不太一樣
主節點提供讀寫,備用節點不提供讀寫。如果主節點掛了,就切換到備用節點,原來的備用節點升級為主節點提供讀寫服務,當原來的主節點恢復運行后,原來的主節點就變成備用節點
2. 遠程模式
遠程模式可以實現雙活的一種模式,簡稱 shovel 模式,所謂的 shovel 就是把消息進行不同數據中心的復制工作,可以跨地域的讓兩個 MQ 集群互聯,遠距離通信和復制。
- Shovel 就是我們可以把消息進行數據中心的復制工作,我們可以跨地域的讓兩個 MQ 集群互聯。
如上圖,有兩個異地的 MQ 集群(可以是更多的集群),當用戶在地區 1 這里下單了,系統發消息到 1 區的 MQ 服務器,發現 MQ 服務已超過設定的閾值,負載過高,這條消息就會被轉到 地區 2 的 MQ 服務器上,由 2 區的去執行后面的業務邏輯,相當於分攤我們的服務壓力。
3. 鏡像模式
非常經典的 mirror 鏡像模式,保證 100% 數據不丟失。在實際工作中也是用得最多的,並且實現非常的簡單,一般互聯網大廠都會構建這種鏡像集群模式。
如上圖,用 KeepAlived 做了 HA-Proxy 的高可用,然后有 3 個節點的 MQ 服務,消息發送到主節點上,主節點通過 mirror 隊列把數據同步到其他的 MQ 節點,這樣來實現其高可靠
4. 多活模式
也是實現異地數據復制的主流模式,因為 shovel 模式配置比較復雜,所以一般來說,實現異地集群的都是采用這種雙活 或者 多活模型來實現的。這種模式需要依賴 rabbitMQ 的 federation 插件,可以實現持續的,可靠的 AMQP 數據通信,多活模式在實際配置與應用非常的簡單
rabbitMQ 部署架構采用雙中心模式(多中心),那么在兩套(或多套)數據中心各部署一套 rabbitMQ 集群,各中心的 rabbitMQ 服務除了需要為業務提供正常的消息服務外,中心之間還需要實現部分隊列消息共享。
federation 插件是一個不需要構建 cluster ,而在 brokers 之間傳輸消息的高性能插件,federation 插件可以在 brokers 或者 cluster 之間傳輸消息,連接的雙方可以使用不同的 users 和 virtual hosts,雙方也可以使用不同版本的 rabbitMQ 和 erlang。federation 插件使用 AMQP 協議通信,可以接受不連續的傳輸。federation 不是建立在集群上的,而是建立在單個節點上的,如圖上黃色的 rabbit node 3 可以與綠色的 node1、node2、node3 中的任意一個利用 federation 插件進行數據同步。
IV. 其他
0. 項目
1. 相關博文
- RabbitMQ Tutorials
- MQ 和 RabbitMQ 作用特點
- RabbitMq 基礎教程之基本概念
- RabbitMQ 學習(六)——消息確認機制(Confirm 模式)
- RabbitMQ 的 4 種集群架構
- Rabbitmq 是如何來保證事務的
- rabbitmq 消息一致性問題
2. 一灰灰 Blog
盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激
下面一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
- 一灰灰 Blog 個人博客 https://blog.hhui.top
- 一灰灰 Blog-Spring 專題博客 http://spring.hhui.top