★訊息佇列16篇
1 認識RocketMQ
RocketMQ是一款基於Java開發的分散式訊息中介軟體,它以其高效能、高可靠性、高實時性以及分散式特性而廣受好評。
它支援事務訊息、順序訊息、批次訊息、定時訊息、訊息回溯等。網際網路場景中經常使用RocketMQ進行訊息路由、訂閱釋出、非同步解耦、流量削減峰等操作,來緩解系統的壓力。
2 三種常見的訊息中介軟體比較
特性 | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|
開發語言 | erlang | java | scala |
單機吞吐量 | 1w+ | 10w+ | 10w+ |
時效性 | us級 | ms級 | ms級以內 |
可用性 | 高(主從架構) | 非常高(分散式架構) | 非常高(分散式架構) |
訊息可靠性 | 基本不丟 | 引數化配置和持久化:基本不丟 | 引數化配置和持久化:基本不丟 |
功能特性 | 基於erlang開發,所以併發能力很強,效能極其好,延時很低;管理介面較豐富 | MQ功能比較完備,擴充套件性佳 | 只支援主要的MQ功能,像一些訊息查詢,訊息回溯等功能沒有提供,畢竟是為大資料準備的,在大資料領域應用廣。 |
生態 | 開源、穩定、社群活躍度高 | 阿里開源,交給Apache,社群活躍度低 | Apache開發,開源、高吞吐量、社群活躍度高 |
技術選型決策參考:
(1)中小型軟體,建議選RabbitMQ, 中小型軟體資料量沒那麼大,選訊息中介軟體,應首選功能比較完備的,所以kafka排除。
不考慮rocketmq的原因是,rocketmq是阿里出品,如果阿里放棄維護rocketmq,中小型公司一般抽不出人來進行rocketmq的定製化開發,因此不推薦。
(2)大型軟體公司,根據具體使用在rocketMq和kafka之間二選一。一方面,大型軟體公司,具備足夠的資金搭建分散式環境,也具備足夠大的資料量。
針對rocketMQ,大型軟體公司也可以抽出人手對rocketMQ進行定製化開發,畢竟有能力改JAVA原始碼的人,還是相當多的。
至於kafka,根據業務場景選擇,如果有日誌採集功能,肯定是首選kafka了。具體該選哪個,看使用場景。引入MQ之後,必然導致系統可用性降低,複雜性增大。
3 訊息中介軟體使用場景
1. 解耦: 比如說系統A會交給系統B去處理一些事情,但是A不想直接跟B有關聯,避免耦合太強,就可以透過在A,B中間加入訊息佇列,A將要任務的事情交給訊息佇列 ,B訂閱訊息佇列來執行任務。
這種場景很常見,比如A是訂單系統,B是庫存系統,可以透過訊息佇列把削減庫存的工作交予B系統去處理。如果A系統同時想讓B、C、D...多個系統處理問題的時候,這種優勢就更加明顯了。
2. 有序性: 先進先出原理,先來先處理,比如一個系統處理某件事需要很長一段時間,但是在處理這件事情時候,有其他人也發出了請求,可以把請求放在訊息隊裡,一個一個來處理。
對資料的順序性和一致性有強需求的業務,比如同一張銀行卡同時被多個入口使用,需要保證入賬出賬的順序性,避免出現資料不一致。
3. 訊息路由/資料分發: 按照不同的規則,將佇列中訊息傳送到不同的其他佇列中
透過訊息佇列將不同染色的請求傳送到不同的服務去操作。這樣達成了流量按照業務拆分的目的。
4、非同步處理: 處理一項任務的時候,有3個步驟A、B、C,需要先完成A操作, 然後做B、C 操作。任務執行成功與否強依賴A的結果,但不依賴B、C 的結果。
如果我們使用序列的執行方式,那處理任務的週期就會變長,系統的整體吞吐能力也會降低(在同一個系統中做非同步其實也是比較大的開銷),所以使用訊息佇列是比較好的辦法。
登入操作就是典型的場景:A:執行登入並得到結果、B:記錄登入日誌、C:將使用者資訊和Token寫入快取。 執行完A就可以從登入頁跳到首頁了,B、C讓服務慢慢去消化,不阻塞當前操作。
5、削峰: 將峰值期間的操作削減,比如A同學的整個操作流程包含12個步驟,後續的11個步驟是不需要強關注結果的資料,可以放在訊息佇列中。
4 MQ的概念、結構和原理
4.1 構成說明
RocketMQ主要有四大核心組成部分:NameServer、Broker、Producer以及Consumer四部分。這些角色通常以叢集的方式存在,RocketMQ 基於純Java開發,具有高吞吐量、高可用性、適合大規模分散式系統應用的特點。
- RockerMQ想要啟動,首先需要啟動 NameServer,再啟動 Brober 主機
- Broker 會向 NameServer 註冊對應的路由和服務
- Producer會進行路的發現,向NameServer請求Broker路由資訊,進行訊息的傳送
- Consumer要連通NameServer,獲取到相關的路由資訊,方便我們進行訊息的訂閱
- Broker 主要負責訊息的儲存,不管是生產訊息還是訂閱訊息,訊息的來源都是 Broker,
- 訊息的傳送(Producer)只會發到主節點,然後Broker會進行訊息的同步,同步到從節點,作為消費者(Consumer)也只會優先從Master節點,獲取訊息,進行消費
- Broker主節點不可用或者非常繁忙,會選擇從節點進行消費
1. Producer:
負責生產訊息,一般由業務系統負責。生產者透過呼叫API將訊息傳送到指定的Topic(主題)中。
2. Broker:
訊息儲存中心,負責接收來自Producer的訊息並儲存,同時Consumer也從這裡取得訊息。Broker還儲存與訊息相關的後設資料,包括消費者組、消費進度偏移量、佇列資訊等。每個Broker可以儲存多個Topic的訊息,每個Topic的訊息也可以分片儲存於不同的Broker。在實際部署中,Broker對應一臺伺服器,並分為Master與Slave兩種型別,Master負責讀寫,Slave只負責讀,以此實現資料的備份和負載均衡。
3. Consumer:
負責消費訊息,一般由後臺系統負責。消費者透過訂閱Topic來獲取訊息,並根據業務邏輯進行處理。消費者可以以叢集消費或廣播消費的方式消費訊息。
4. NameServer:
充當路由訊息的提供者,負責儲存Broker的後設資料資訊,並供Producer和Consumer查詢。NameServer被設計成幾乎無狀態的,可以橫向擴充套件,節點之間無通訊。
4.2 基礎概念
4.2.1 Group(分組)
在RocketMQ中,Group功能是其核心特性之一。Group主要分為傳送端Group和消費端Group。
- 傳送端Group:允許將多個傳送者(Producer)組織成一個傳送者組。透過傳送端Group,可以實現對訊息的批次處理和負載均衡,提高系統效能和可靠性。
- 消費端Group:RocketMQ允許消費者同時訂閱多個主題(Topic),這些消費者可以被組織成一個或多個消費組。消費組內的消費者可以共同分擔訊息的消費任務,實現負載均衡和容錯。當某個消費者出現故障時,其他消費者可以接管其消費任務,確保訊息被及時處理。同時,消費組還支援訊息過濾和順序消費等高階特性。
4.2.2 Topic(主題)
用來區分訊息的種類,表示一類訊息的邏輯名字,訊息的邏輯管理單位,無論生產還是消費訊息,都需要執行Topic。比如一個Topic專門用於使用者訂單訊息傳送,一個Topic專門用於扣減或增加積分的。
- 一個傳送者可以傳送訊息給一個或者多個Topic
- 一個訊息接受者可以訂閱一個或多個Topic訊息
4.2.3 Message Queue(訊息佇列)
MessageQueue是RocketMQ中用於儲存和傳輸訊息的資料結構。每個MessageQueue都有一個唯一識別符號,由Topic名稱和佇列編號組成。MessageQueue具有以下特點:
- 唯一標識:確保每個MessageQueue都可以被唯一地識別和定位。
- 訊息順序性:對於同一個MessageQueue中的訊息,RocketMQ保證其消費的順序性,即先進先出(FIFO)。
- 負載均衡:RocketMQ透過動態調整訊息分配策略,將訊息均勻地分佈到所有的MessageQueue中,實現負載均衡,避免某個MessageQueue過載而其他MessageQueue空閒的情況。
- 高可用性:RocketMQ支援將多個Broker節點組成叢集,每個MessageQueue可以在不同的Broker節點上進行主從複製,提供高可用性和資料冗餘。即使某個Broker節點出現故障,其他節點也可以繼續提供服務,確保訊息的可靠傳輸。
4.2.4 Tag(標籤)
Tag是RocketMQ中用於對訊息進行分類和過濾的標記。生產者可以在傳送訊息時指定Tag,消費者可以根據Tag來過濾和訂閱訊息。Tag的使用可以使得訊息的管理和消費更加靈活和高效。例如,一個電商系統可能會根據商品的類別(如服裝、電子產品等)來設定不同的Tag,消費者可以根據這些Tag來訂閱和處理特定類別的訊息。
4.2.5 Offset(偏移量)
Offset在RocketMQ中用於標識消費者在訊息佇列中的位置。每個消費者都會維護一個Offset,以便知道下一次從哪裡開始消費。Offset的使用可以確保訊息不丟失、避免訊息重複消費以及支援訊息的順序消費。
- Message queue 是無限長的陣列。一條訊息進來下標就會漲 1,而這個陣列的下標就是 offset。
- 確保訊息不丟失:透過持久化Offset,即使在消費者當機後重啟,也能從上次消費的位置繼續消費,保證訊息至少被消費一次。
- 避免訊息重複消費:消費者在成功處理訊息後更新Offset,確保每條訊息只被消費一次。
- 支援訊息順序消費:對於順序訊息,透過維護Offset可以保證訊息的順序消費。
5 程式實現
5.1 Java中引入和實現RocketMQ
-
引入依賴
在Java專案中,通常透過Maven或Gradle等構建工具來引入RocketMQ的客戶端依賴。以Maven為例,可以在
pom.xml
檔案中新增以下依賴:<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>最新版本號(5.3.1)</version> </dependency>
-
實現生產者
在Java中,透過建立
DefaultMQProducer
物件來實現訊息的生產者。生產者需要設定NameServer地址,並呼叫start()
方法初始化。然後,可以建立Message
物件並設定主題、標籤和訊息內容,最後呼叫send()
方法傳送訊息。public class Producer { public static void main(String[] args) throws Exception { // 建立一個訊息生產者,並設定訊息生產者組 DefaultMQProducer producer = new DefaultMQProducer("your_producer_group"); // 指定NameServer地址 producer.setNamesrvAddr("your_nameserver_address"); // 初始化Producer producer.start(); // 建立訊息物件,並設定主題、標籤和訊息內容 Message msg = new Message("your_topic", "your_tag", "Hello RocketMQ".getBytes()); // 傳送訊息並獲取傳送結果 SendResult sendResult = producer.send(msg); System.out.printf("%s%n", sendResult); // 關閉生產者例項 producer.shutdown(); } }
-
實現消費者
在Java中,透過建立
DefaultMQPushConsumer
物件來實現訊息的消費者。消費者需要設定NameServer地址和消費組名稱,並呼叫subscribe()
方法訂閱主題和標籤。然後,註冊訊息監聽器來處理接收到的訊息。public class Consumer { public static void main(String[] args) throws Exception { // 建立一個訊息消費者,並設定訊息消費者組 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("your_consumer_group"); // 指定NameServer地址 consumer.setNamesrvAddr("your_nameserver_address"); // 訂閱指定Topic下的所有訊息 consumer.subscribe("your_topic", "*"); // 註冊訊息監聽器 consumer.registerMessageListener(new MessageListenerConcurrently() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for (MessageExt msg : msgs) { System.out.printf("接收到訊息: %s%n", new String(msg.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // 啟動消費者例項 consumer.start(); } }
6 總結
本文只是瞭解下RocketMQ的基本原理和實現,在後面的章節中,我們會帶來RocketMQ的完整解讀。