本文根據阿里雲 RocketMQ產品文檔整理
地址:https://help.aliyun.com/document_detail/29532.html?userCode=qtldtin2
簡介
RocketMQ是由阿里捐贈給Apache的一款低延遲、高並發、高可用、高可靠的分布式消息中間件。經歷了淘寶雙十一的洗禮。RocketMQ既可為分布式應用系統提供異步解耦和削峰填谷的能力,同時也具備互聯網應用所需的海量消息堆積、高吞吐、可靠重試等特性。
核心概念
- Topic:消息主題,一級消息類型,生產者向其發送消息。
- Message:生產者向Topic發送並最終傳送給消費者的數據消息的載體。
- 消息屬性:生產者可以為消息定義的屬性,包含Message Key和Tag。
- Message Key:消息的業務標識,由消息生產者(Producer)設置,唯一標識某個業務邏輯。
- Message ID:消息的全局唯一標識,由消息隊列RocketMQ系統自動生成,唯一標識某條消息。
- Tag:消息標簽,二級消息類型,用來進一步區分某個Topic下的消息分類
- Producer:也稱為消息發布者,負責生產並發送消息至Topic。
- Consumer:也稱為消息訂閱者,負責從Topic接收並消費消息。
- 分區:即Topic Partition,物理上的概念。每個Topic包含一個或多個分區。
- 消費位點:每個Topic會有多個分區,每個分區會統計當前消息的總條數,這個稱為最大位點MaxOffset;分區的起始位置對應的位置叫做起始位點MinOffset。
- Group:一類生產者或消費者,這類生產者或消費者通常生產或消費同一類消息,且消息發布或訂閱的邏輯一致。
- Group ID:Group的標識。
- 隊列:個Topic下會由一到多個隊列來存儲消息。
- Exactly-Once投遞語義:Exactly-Once投遞語義是指發送到消息系統的消息只能被Consumer處理且僅處理一次,即使Producer重試消息發送導致某消息重復投遞,該消息在Consumer也只被消費一次。
- 集群消費:一個Group ID所標識的所有Consumer平均分攤消費消息。例如某個Topic有9條消息,一個Group ID有3個Consumer實例,那么在集群消費模式下每個實例平均分攤,只消費其中的3條消息。
- 廣播消費:一個Group ID所標識的所有Consumer都會各自消費某條消息一次。例如某個Topic有9條消息,一個Group ID有3個Consumer實例,那么在廣播消費模式下每個實例都會各自消費9條消息。
- 定時消息:Producer將消息發送到消息隊列RocketMQ服務端,但並不期望這條消息立馬投遞,而是推遲到在當前時間點之后的某一個時間投遞到Consumer進行消費,該消息即定時消息。
- 延時消息:Producer將消息發送到消息隊列RocketMQ服務端,但並不期望這條消息立馬投遞,而是延遲一定時間后才投遞到Consumer進行消費,該消息即延時消息。
- 事務消息:RocketMQ提供類似X/Open XA的分布事務功能,通過消息隊列RocketMQ的事務消息能達到分布式事務的最終一致。
- 順序消息:RocketMQ提供的一種按照順序進行發布和消費的消息類型,分為全局順序消息和分區順序消息。
- 全局順序消息:對於指定的一個Topic,所有消息按照嚴格的先入先出(FIFO)的順序進行發布和消費。
- 分區順序消息:對於指定的一個Topic,所有消息根據Sharding Key進行區塊分區。同一個分區內的消息按照嚴格的FIFO順序進行發布和消費。Sharding Key是順序消息中用來區分不同分區的關鍵字段,和普通消息的Message Key是完全不同的概念。
- 消息堆積:Producer已經將消息發送到消息隊列RocketMQ的服務端,但由於Consumer消費能力有限,未能在短時間內將所有消息正確消費掉,此時在消息隊列RocketMQ的服務端保存着未被消費的消息,該狀態即消息堆積。
- 消息過濾:Consumer可以根據消息標簽(Tag)對消息進行過濾,確保Consumer最終只接收被過濾后的消息類型。消息過濾在消息隊列RocketMQ的服務端完成。
- 消息軌跡:在一條消息從Producer發出到Consumer消費處理過程中,由各個相關節點的時間、地點等數據匯聚而成的完整鏈路信息。通過消息軌跡,您能清晰定位消息從Producer發出,經由消息隊列RocketMQ服務端,投遞給Consumer的完整鏈路,方便定位排查問題。
- 重置消費位點:以時間軸為坐標,在消息持久化存儲的時間范圍內(默認3天),重新設置Consumer對已訂閱的Topic的消費進度,設置完成后Consumer將接收設定時間點之后由Producer發送到消息隊列RocketMQ服務端的消息。
- 死信隊列:死信隊列用於處理無法被正常消費的消息。當一條消息初次消費失敗,消息隊列RocketMQ會自動進行消息重試;達到最大重試次數后,若消費依然失敗,則表明Consumer在正常情況下無法正確地消費該消息。此時,消息隊列RocketMQ不會立刻將消息丟棄,而是將這條消息發送到該Consumer對應的特殊隊列中。
消息隊列RocketMQ將這種正常情況下無法被消費的消息稱為死信消息(Dead-Letter Message),將存儲死信消息的特殊隊列稱為死信隊列(Dead-Letter Queue)。
消息收發模型
消息隊列RocketMQ支持發布和訂閱模型,消息生產者應用創建Topic並將消息發送到Topic。消費者應用創建對Topic的訂閱以便從其接收消息。通信可以是一對多(扇出)、多對一(扇入)和多對多。具體通信如下圖所示。
-
生產者集群:用來表示發送消息應用,一個生產者集群下包含多個生產者實例,可以是多台機器,也可以是一台機器的多個進程,或者一個進程的多個生產者對象。
一個生產者集群可以發送多個Topic消息。發送分布式事務消息時,如果生產者中途意外宕機,消息隊列RocketMQ服務端會主動回調生產者集群的任意一台機器來確認事務狀態。 -
消費者集群:用來表示消費消息應用,一個消費者集群下包含多個消費者實例,可以是多台機器,也可以是多個進程,或者是一個進程的多個消費者對象。
一個消費者集群下的多個消費者以均攤方式消費消息。如果設置的是廣播方式,那么這個消費者集群下的每個實例都消費全量數據。
一個消費者集群對應一個Group ID,一個Group ID可以訂閱多個Topic,如上圖中的Group 2所示。Group和Topic的訂閱關系可以通過直接在程序中設置即可。
應用場景
-
削峰填谷:諸如秒殺、搶紅包、企業開門紅等大型活動時皆會帶來較高的流量脈沖,或因沒做相應的保護而導致系統超負荷甚至崩潰,或因限制太過導致請求大量失敗而影響用戶體驗,消息隊列RocketMQ可提供削峰填谷的服務來解決該問題。
-
異步解耦:交易系統作為淘寶和天貓主站最核心的系統,每筆交易訂單數據的產生會引起幾百個下游業務系統的關注,包括物流、購物車、積分、流計算分析等等,整體業務系統龐大而且復雜,消息隊列RocketMQ可實現異步通信和應用解耦,確保主站業務的連續性。
-
順序收發:細數日常中需要保證順序的應用場景非常多,例如證券交易過程時間優先原則,交易系統中的訂單創建、支付、退款等流程,航班中的旅客登機消息處理等等。與先進先出FIFO(First In First Out)原理類似,消息隊列RocketMQ提供的順序消息即保證消息FIFO。
-
分布式事務一致性:交易系統、支付紅包等場景需要確保數據的最終一致性,大量引入消息隊列RocketMQ的分布式事務,既可以實現系統之間的解耦,又可以保證最終的數據一致性。
-
大數據分析:數據在“流動”中產生價值,傳統數據分析大多是基於批量計算模型,而無法做到實時的數據分析,利用阿里雲消息隊列RocketMQ與流式計算引擎相結合,可以很方便的實現業務數據的實時分析。
-
分布式緩存同步:天貓雙11大促,各個分會場琳琅滿目的商品需要實時感知價格變化,大量並發訪問數據庫導致會場頁面響應時間長,集中式緩存因帶寬瓶頸,限制了商品變更的訪問流量,通過消息隊列RocketMQ構建分布式緩存,實時通知商品數據的變化。
下文先以用戶注冊為場景說明消息隊列RocketMQ如何實現以下功能:
- 異步解耦
- 分布式事務的數據一致性
- 消息的順序收發
最后,再以電商的秒殺場景和價格同步場景分別說明消息隊列RocketMQ所實現的削峰填谷和大規模機器的緩存同步。
異步解耦
傳統處理
最常見的一個場景是用戶注冊后,需要發送注冊郵件和短信通知,以告知用戶注冊成功。傳統的做法有以下兩種:
-
串行方式
數據流動如下所述:
- 您在注冊頁面填寫賬號和密碼並提交注冊信息,這些注冊信息首先會被寫入注冊系統。
- 注冊信息寫入注冊系統成功后,再發送請求至郵件通知系統。郵件通知系統收到請求后向用戶發送郵件通知。
- 郵件通知系統接收注冊系統請求后再向下游的短信通知系統發送請求。短信通知系統收到請求后向用戶發送短信通知。
以上三個任務全部完成后,才返回注冊結果到客戶端,用戶才能使用賬號登錄。
假設每個任務耗時分別為50 ms,則用戶需要在注冊頁面等待總共150 ms才能登錄。 -
並行方式
數據流動如下所述:
- 用戶在注冊頁面填寫賬號和密碼並提交注冊信息,這些注冊信息首先會被寫入注冊系統。
- 注冊信息寫入注冊系統成功后,再同時發送請求至郵件和短信通知系統。郵件和短信通知系統收到請求后分別向用戶發送郵件和短信通知。
以上兩個任務全部完成后,才返回注冊結果到客戶端,用戶才能使用賬號登錄。
假設每個任務耗時分別為50 ms,其中,郵件和短信通知並行完成,則用戶需要在注冊頁面等待總共100 ms才能登錄。
異步解耦
對於用戶來說,注冊功能實際只需要注冊系統存儲用戶的賬戶信息后,該用戶便可以登錄,后續的注冊短信和郵件不是即時需要關注的步驟。
對於注冊系統而言,發送注冊成功的短信和郵件通知並不一定要綁定在一起同步完成,所以實際當數據寫入注冊系統后,注冊系統就可以把其他的操作放入對應的消息隊列RocketMQ中然后馬上返回用戶結果,由消息隊列RocketMQ異步地進行這些操作。
數據流動如下所述:
- 用戶在注冊頁面填寫賬號和密碼並提交注冊信息,這些注冊信息首先會被寫入注冊系統。
- 注冊信息寫入注冊系統成功后,再發送消息至消息隊列RocketMQ。消息隊列RocketMQ會馬上返回響應給注冊系統,注冊完成。用戶可立即登錄。
- 下游的郵件和短信通知系統訂閱消息隊列RocketMQ的此類注冊請求消息,即可向用戶發送郵件和短信通知,完成所有的注冊流程。
用戶只需在注冊頁面等待注冊數據寫入注冊系統和消息隊列RocketMQ的時間,即等待55 ms即可登錄。
異步解耦是消息隊列RocketMQ的主要特點,主要目的是減少請求響應時間和解耦。主要的適用場景就是將比較耗時而且不需要即時(同步)返回結果的操作作為消息放入消息隊列。同時,由於使用了消息隊列RocketMQ,只要保證消息格式不變,消息的發送方和接收方並不需要彼此聯系,也不需要受對方的影響,即解耦。
分布式事務的數據一致性
注冊系統注冊的流程中,用戶入口在網頁注冊系統,通知系統在郵件系統,兩個系統之間的數據需要保持最終一致。
普通消息處理
如上所述,注冊系統和郵件通知系統之間通過消息隊列進行異步處理。注冊系統將注冊信息寫入注冊系統之后,發送一條注冊成功的消息到消息隊列RocketMQ,郵件通知系統訂閱消息隊列RocketMQ的注冊消息,做相應的業務處理,發送注冊成功或者失敗的郵件。
流程說明如下:
- 注冊系統發起注冊。
- 注冊系統向消息隊列RocketMQ發送注冊消息成功與否的消息。
2.1. 消息發送成功,進入3。
2.2. 消息發送失敗,導致郵件通知系統未收到消息隊列RocketMQ發送的注冊成功與否的消息,而無法發送郵件,最終郵件通知系統和注冊系統之間的狀態數據不一致。 - 郵件通知系統收到消息隊列RocketMQ的注冊成功消息。
- 郵件通知系統發送注冊成功郵件給用戶。
在這樣的情況下,雖然實現了系統間的解耦,上游系統不需要關心下游系統的業務處理結果;但是數據一致性不好處理,如何保證郵件通知系統狀態與注冊系統狀態的最終一致。
事務消息處理
此時,需要利用消息隊列RocketMQ所提供的事務消息來實現系統間的狀態數據一致性。
流程說明如下:
-
注冊系統向消息隊列RocketMQ發送半事務消息。
1.1. 半事務消息發送成功,進入2。
1.2. 半事務消息發送失敗,注冊系統不進行注冊,流程結束。(最終注冊系統與郵件通知系統數據一致) -
注冊系統開始注冊。
2.1. 注冊成功,進入3.1。
2.2. 注冊失敗,進入3.2。 -
注冊系統向消息隊列RocketMQ發送半消息狀態。
3.1. 提交半事務消息,產生注冊成功消息,進入4。
3.2. 回滾半事務消息,未產生注冊成功消息,流程結束。
說明 最終注冊系統與郵件通知系統數據一致。 -
郵件通知系統接收消息隊列RocketMQ的注冊成功消息。
-
郵件通知系統發送注冊成功郵件。(最終注冊系統與郵件通知系統數據一致)
關於分布式事務消息的更多詳細內容,請參見事務消息。
消息的順序收發
消息隊列RocketMQ順序消息分為兩種情況:
- 全局順序:對於指定的一個Topic,所有消息將按照嚴格的先入先出(FIFO)的順序,進行順序發布和順序消費。
- 分區順序:對於指定的一個Topic,所有消息根據Sharding Key進行區塊分區,同一個分區內的消息將按照嚴格的FIFO的順序,進行順序發布和順序消費,可以保證一個消息被一個進程消費。
在注冊場景中,可使用用戶ID作為Sharding Key來進行分區,同一個分區下的新建、更新或刪除注冊信息的消息必須按照FIFO的順序發布和消費。
削峰填谷
流量削峰也是消息隊列RocketMQ的常用場景,一般在秒殺或團隊搶購活動中使用廣泛。
在秒殺或團隊搶購活動中,由於用戶請求量較大,導致流量暴增,秒殺的應用在處理如此大量的訪問流量后,下游的通知系統無法承載海量的調用量,甚至會導致系統崩潰等問題而發生漏通知的情況。為解決這些問題,可在應用和下游通知系統之間加入消息隊列RocketMQ。
秒殺處理流程如下所述:
- 用戶發起海量秒殺請求到秒殺業務處理系統。
- 秒殺處理系統按照秒殺處理邏輯將滿足秒殺條件的請求發送至消息隊列RocketMQ。
- 下游的通知系統訂閱消息隊列RocketMQ的秒殺相關消息,再將秒殺成功的消息發送到相應用戶。
- 用戶收到秒殺成功的通知。
大規模機器的緩存同步
雙十一大促時,各個分會場會有玲琅滿目的商品,每件商品的價格都會實時變化。使用緩存技術也無法滿足對商品價格的訪問需求,緩存服務器網卡滿載。訪問較多次商品價格查詢影響會場頁面的打開速度。
此時需要提供一種廣播機制,一條消息本來只可以被集群的一台機器消費,如果使用消息隊列RocketMQ的廣播消費模式,那么這條消息會被所有節點消費一次,相當於把價格信息同步到需要的每台機器上,取代緩存的作用。
系統部署架構
系統部署架構如下圖所示。
圖中所涉及到的概念如下所述:
- Name Server:是一個幾乎無狀態節點,可集群部署,在消息隊列RocketMQ版中提供命名服務,更新和發現Broker服務。
- Broker:消息中轉角色,負責存儲消息,轉發消息。分為Master Broker和Slave Broker,一個Master Broker可以對應多個Slave Broker,但是一個Slave Broker只能對應一個Master Broker。Broker啟動后需要完成一次將自己注冊至Name Server的操作;隨后每隔30s定期向Name Server上報Topic路由信息。
- 生產者:與Name Server集群中的其中一個節點(隨機)建立長鏈接(Keep-alive),定期從Name Server讀取Topic路由信息,並向提供Topic服務的Master Broker建立長鏈接,且定時向Master Broker發送心跳。
- 消費者:與Name Server集群中的其中一個節點(隨機)建立長連接,定期從Name Server拉取Topic路由信息,並向提供Topic服務的Master Broker、Slave Broker建立長連接,且定時向Master Broker、Slave Broker發送心跳。Consumer既可以從Master Broker訂閱消息,也可以從Slave Broker訂閱消息,訂閱規則由Broker配置決定。
歡迎掃碼或微信搜索公眾號《程序員果果》關注我,關注有驚喜~