MQ 是什麼?
MQ(Message Queue)訊息佇列
用佇列機制來實現軟體之間的通訊,消費者可以到指定佇列拉取訊息,或者訂閱相應的佇列,由MQ服務端給其推送訊息
什麼是佇列?
是一種資料結構,遵循 FIFO (先進先出)原則
憑啥要使用 MQ , MQ 有啥優勢?
- 非同步通訊
將以前也不中不必要的同步操作,優化成非同步操作,提高效能
- 業務解耦
將原有A模組直接呼叫B模組的介面,優化成,A模組的請求給到MQ,A模組的事情就做完了
MQ會主動推給B模組,或者B模組自己來拉
- 流量削峰
當某一時間大量的流量打到伺服器上,伺服器一時間無法承受,會當機
這個時候,若請求都是從訊息佇列裡面出來,則能夠保證這種大流量的情況下,伺服器仍然能夠有序的穩定的處理請求
MQ 有啥劣勢呢?
- 系統可用性降低,對外部有依賴了
- 需要考慮 MQ 訊息丟失,重複消費的問題
- 需要花費精力保證訊息的順序性,一致性
常用 MQ 效能對比
ActiveMQ | RabbitMQ | RocketMQ | Kafka | |
---|---|---|---|---|
開發語言 | java | erlang | java | scala |
單機吞吐量 | 萬級 | 萬級 | 十萬級 | 十萬級 |
時效性 | ms級 | us級 | ms級 | ms級以內 |
可用性 | 高 主從架構 |
高 主從架構 |
非常高 分散式架構 |
非常高 分散式架構 |
訊息可靠性 | 較低概率丟失訊息 | 基本不丟 | 可以做到基本不丟 | 可以做到基本不丟 |
功能支援 | 支援功能全 | 效能好 延時低 併發能力強 |
MQ 功能較完善 支援分散式,擴充套件性好 |
主要用於大資料和日誌採集 |
MQ 如何避免訊息堆積
- 提高消費速率(叢集的方式)
- 消費者批量獲取訊息進行消費
MQ 如何避免消費者重複消費(冪等性問題)
- 全域性ID(增加標誌位) + 保證業務一致性
MQ 如何保證訊息不丟失
- 訊息確認機制
- 持久化
- 訊息 ACK
MQ 如何保證訊息順序一致性
- 繫結同一個消費者和佇列
MQ 推與拉取架構模型是怎麼樣的?
- MQ 伺服器與消費者建立長連線後,MQ 伺服器會主動推資料給到消費者
- 當消費者第一次啟動的時候,會去找MQ 伺服器拉資料
mq有哪些消費模式
推模式
註冊一個消費者後,RabbitMQ會在訊息可用時,自動將訊息進行推送給消費者。這種方式效率最高最及時。拉模式
屬於一種輪詢模型,傳送一次get請求,獲得一個訊息。如果此時RabbitMQ中沒有訊息,會獲得一個表示空的回覆。自動確認
消費者消費訊息的時候,將自動向RabbitMQ進行確認。
- 手動確認
消費者消費訊息的時候,手動呼叫相應函式進行ack 應答
- qos預取模式
在確認訊息被接收之前,消費者可以預先要求接收一定數量的訊息,在處理完一定數量的訊息後,批量進行確認
當然,如果消費者應用程式在確認訊息之前崩潰,則所有未確認的訊息將被重新傳送給其他消費者
RabbitMQ
中既然有了connections
為什麼還要有 channel
?
connection 是什麼
connection 是 生產者或消費者與 RabbitMQ Broker 建立的連線,是一個TCP連線
一旦 TCP 連線建立起來,客戶端緊接著可以建立一個 AMQP 通道(Channel),每個通道都會被指派一個唯一的 ID
通道是建立在 Connection 之上的虛擬連線,多個通道複用一個TCP連線,可以減少效能開銷,同時也便於管理
因為一個應用需要向RabbitMQ 中生成或者消費訊息的話,都要建一個TCP連線,TCP連線開銷非常大,如果遇到使用高峰,效能瓶頸也隨之顯現
通道複用連線優勢:
- 複用TCP連線,減少效能開銷,便於管理
- RabbitMQ 保障每一個通道的私密性
當每個通道的流量不是很大時,複用單一的 Connection 可以在產生效能瓶頸的情況下有效地節省 TCP 連線資源
通道本身的流量很大時,這時候多個通道複用一個 Connection 就會產生效能瓶頸,進而使整體的流量被限制了,此時就需要開闢多個 Connection,將這些通道均攤到這些 Connection 中
RabbitMQ
的作用
- 削峰填谷
- 生產者和消費者業務解耦
- 服務間非同步通訊
- 定時任務
- 順序消費
為什麼選擇 RabbitMQ
現在的市面上有很多 MQ 可以選擇,比如 ActiveMQ、ZeroMQ、Appche Qpid為什麼要選擇 RabbitMQ?
- 除了 Qpid,RabbitMQ 是唯一一個實現了 AMQP 標準的訊息伺服器
- 可靠性,RabbitMQ 的持久化支援,保證了訊息的穩定性
- 高併發,RabbitMQ 使用了 Erlang 開發語言,Erlang 是為電話交換機開發的語言,天生自帶高併發光環,和高可用特性
- 叢集部署簡單,正是應為 Erlang 使得 RabbitMQ 叢集部署變的超級簡單
- 社群活躍度高,根據網上資料來看,RabbitMQ 也是首選
RabbitMQ 的特點是什麼?
可靠
RabbitMQ 使用 如持久化、傳輸確認及釋出確認等機制來保證可靠性
靈活的路由
通過交換器來路由訊息
對於典型的路由功能, RabbitMQ 己經提供了一些內建的交換器來實現
針對更復雜的路由功能,可以將多個 交換器繫結在一起,這個就需要通過外掛來實現了
- 擴充套件性
多個 RabbitMQ 節點可以組成一個叢集,也可以根據實際業務情況動態地擴充套件叢集中節點
- 高可用性
佇列可以在叢集中的機器上設定映象,使得在部分節點出現問題的情況下佇列仍然可用
- 支援的協議多
RabbitMQ 除了原生支援 AMQP 協議,還支援 STOMP, MQTT等多種訊息中介軟體協議
- 多語言客戶端
RabbitMQ 幾乎支援所有常用語言,比如 GO、 Java、 Python、 Ruby、 PHP等
- WEB 管理介面
RabbitMQ 提供了一個易用的使用者介面,使得使用者可以監控和管理訊息、叢集中的節點等
- 命令外掛機制
RabbitMQ 提供了許多外掛 , 以實現從多方面進行擴充套件,當然也可以編寫自己的外掛
生產者Producer和消費者Consumer 有哪些知識點?
生產者
- 訊息生產者,投遞訊息
- 訊息一般包含兩個部分:訊息體(
payload
)和標籤(Label
)
消費者
消費訊息,接收訊息
消費者連線到 RabbitMQ 伺服器,並訂閱到佇列
消費訊息時只消費訊息體,丟棄標籤
RabbitMQ 訊息持久化中的坑
預設情況下重啟伺服器會導致訊息丟失,我們如何保證重啟 RabbitMQ 不丟失資料?
那就是做持久化,持久化需要滿足如下三個條件才可以恢復 RabbitMQ 的資料
- 投遞訊息的時候 durable 設定為 true,訊息持久化
- 訊息已經到達持久化交換器上
- 訊息已經到達持久化的佇列上
持久化的工作原理
Rabbit 會將持久化訊息寫入磁碟上的持久化日誌檔案,等訊息被消費之後,Rabbit 會把這條訊息標識為等待垃圾回收
持久化的優缺點
優點
- 資料持久化,資料不丟失
缺點
- 對效能有影響,寫硬碟比寫記憶體效能低,從而降低服務的吞吐量
RabbitMQ ACK 應答機制
ACK 應答分為手動和自動,各有優劣
如果訊息不太重要,丟失也沒有影響,那麼自動 ACK 會比較方便
如果訊息非常重要,不容丟失。那麼最好在消費完成後手動 ACK
否則接收訊息後就自動 ACK,RabbitMQ 就會把訊息從佇列中刪除。若此時消費者當機或處理業務失敗,那麼訊息就丟失了
ACK 機制的開發注意事項
如果忘記了 ACK,那麼後果很嚴重
當 Consumer 退出時候,Message 會一直重新分發。然後 RabbitMQ 會佔用越來越多的內容,由於 RabbitMQ 會長時間執行,這個” 記憶體洩漏” 是致命的
為什麼需要限流,消費者流量控制
- 某一時刻,生產者在 RabbitMQ 佇列中堆積了很多訊息,此時有一個消費者啟動,大量的訊息會推送到消費者上面,這種瞬時大流量會把消費者打掛
- 生產者和消費者效率不平衡的情況,會導致消費者端效能下降,服務端卡頓或者崩潰
RabbitMQ 的組成
- 生產者 producer
- 消費者 consumer
- 交換機 exchange
用於接受、分配訊息
- 訊息 message
- 佇列 queue
用於儲存生產者的訊息
- 通道 channel AMQP
訊息推送使用的通道
- 連線 connections
生成者或者消費者與Rabbit 建立的TCP 連線
- 路由鍵 routingKey
用於把生成者的資料分配到交換器上
- 繫結鍵 BindingKey
用於把交換器的訊息繫結到佇列上
- 連線管理器 ConnectionFactory
應用程式與 Rabbit 之間建立連線的管理器,程式程式碼中使用
- VHost
vhost 可以理解為虛擬 broker,即虛擬機器
其內部均含有獨立的 queue、exchange 和 binding 等
擁有獨立的許可權系統,做到資源隔離,資源高效利用
RabbitMQ 的六種模式
- single
簡單的生產者生產訊息,放入佇列,消費者消費訊息
- work
當生產者生產訊息的速度大於消費者消費的速度,就要考慮用 work 工作模式,這樣能提高處理速度提高負載
work 模式與 single 模式類似, 只是work 模式比 single 模式多了一些消費者
- publish
應用場景:簡單訊息佇列的使用,一個生產者一個消費者
- routing
訊息生產者將訊息傳送給交換機按照路由判斷,路由是字串(info) 當前產生的訊息攜帶路由字元(物件的方法),交換機根據路由的key
只能匹配上路由key對應的訊息佇列,對應的消費者才能消費訊息
- topic
話題模式,一個訊息被多個消費者獲取,訊息的目標 queue 可用 BindingKey 以萬用字元
- rpc
通過遠端過程呼叫的方式實現
儲存機制
- 持久化訊息
持久化的訊息在到達佇列時就被寫入磁碟,持久化的訊息也會在記憶體中儲存一份備份,這樣可以提高一定的效能,當記憶體吃緊的時候會從記憶體中清除
- 非持久化訊息
一般只儲存在記憶體中,在記憶體吃緊的時候會被換入到磁碟中,以節省記憶體空間
RabbitMQ中訊息可能有的幾種狀態
- alpha
訊息內容(包括訊息體、屬性和 headers) 和訊息索引都儲存在記憶體中
beta
訊息內容儲存在磁碟中,訊息索引儲存在記憶體中
gamma
訊息內容儲存在磁碟中,訊息索引在磁碟和記憶體中都有
- delta
訊息內容和索引都在磁碟中
RabbitMQ 的佇列結構?
- rabbit_amqqueue_process
負責協議相關的訊息處理,即接收生產者釋出的訊息、向消費者交付訊息、處理訊息的確認等
- backing_queue
是訊息儲存的具體形式和引擎,並向 rabbit_amqqueue_process 提供相關的介面以供呼叫
交換器無法根據自身型別和路由鍵找到符合條件佇列時,會如何處理?
我們對交換機設定引數的時候,有一個標誌叫做 mandatory
- 當mandatory標誌位設定為true時
如果exchange根據自身型別和訊息routingKey無法找到一個合適的queue儲存訊息,那麼broker就會呼叫basic.return方法將訊息返還給生產者
- 當mandatory設定為false時
前置條件和上述保持一致,此時 broker會直接將訊息丟棄
如何保證訊息可靠性嘞?
- 訊息從生產者到 MQ
由事務機制,確認機制 來保障
- MQ 自身可靠性
由持久化、叢集、普通模式、映象模式來保證
- MQ 訊息到消費者
由basicAck機制、死信佇列、訊息補償等機制來保證
叢集中的節點型別有哪些?
- 記憶體節點
ram,將變更寫入記憶體。
- 磁碟節點
disc,磁碟寫入操作
RabbitMQ中 要求最少有一個磁碟節點
如何保證 RabbitMQ 訊息佇列的高可用?
RabbitMQ中有三種模式來保證:
- 單機模式
一般是本地啟動,自己學習和測試使用,不會用在生產環境上
- 普通叢集模式
在多臺機器上啟動多個 RabbitMQ 例項,每個機器啟動一個
- 映象叢集模式
RabbitMQ的高可用模式
跟普通叢集模式不一樣的是,建立的 queue,無論後設資料(後設資料指 RabbitMQ 的配置資料)還是 queue 裡的訊息都會存在於多個例項上,
然後每次寫訊息到 queue 的時候,都會自動把訊息到多個例項的 queue 裡進行訊息同步
參考資料:
歡迎點贊,關注,收藏
朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力
好了,本次就到這裡
技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
我是小魔童哪吒,歡迎點贊關注收藏,下次見~
本作品採用《CC 協議》,轉載必須註明作者和本文連結