RocketMQ系列(一)——基礎篇
前言
本篇是RocketMQ系列的第一篇,主要針對對RocketMQ感興趣或想系統學習RocketMQ的同學,內容相對基礎,包括各種名稱與術語解釋、叢集架構以及所支援的各種特性與適用場景。想深入瞭解其原理的請閱讀後面的章節。
RocketMQ系列(二)——應用篇
RocketMQ系列(三)——原理篇
RocketMQ是一款分散式訊息中介軟體,由阿里巴巴中介軟體團隊開發並用於生產環境,2016年捐贈給Apache開源基金會,隨後成為Apache的頂級專案。
常見的訊息中介軟體還包括:RabbitMQ、Kafka、ActiveMQ,另外Redis也可以作為訊息中介軟體的一種簡單實現。
一、名詞解釋
Producer
Producer :訊息的生產者,負責產生訊息,如:使用者完成支付後產生一條交易成功訊息。一個producer例項可以往多個topic傳送訊息。
Producer Group:一類producer的集合,這類producer通常傳送同一種類型的訊息,且傳送邏輯一致。如:不同應用節點 or 不同渠道的交易訂單屬於同一類訊息。
一般來說,在同一應用節點(JVM)的同一套配置中(通過unitName劃分,系列三原理篇會說明),一個Producer Group只能有一個producer例項。
如果事務訊息出現異常,同一Group中的其它producer節點可以執行(服務端的)提交或回滾操作。
Consumer
Consumer:訊息的消費者,負責消費訊息,如:活動服務接收到交易成功訊息後向使用者發放優惠券。一個consumer例項可以訂閱多個topic。
Consumer Group:一類consumer的集合名稱,這類consumer消費同一類訊息,且消費邏輯一致。
與Producer Group類似,在同一應用節點(JVM)的同一套配置中,一個Consumer Group只能有一個consumer例項。
Push Consumer:consumer的一種,應用程式向consumer物件註冊一個Listener介面(MessageListener),一旦收到訊息,consumer會回撥Listener介面的方法。
Pull Consumer:consumer的一種,應用程式主動從broker拉取訊息,主動權由應用程式控制。
Broker
訊息中轉角色,一般也稱為Server,負責儲存和接受訊息拉取請求,producer傳送的訊息順序儲存在broker的queue中。
broker的角色分為Master(主節點)和Slave(從節點),區別主要在於訊息只能往Master節點寫入,從節點被動從Master同步資料。
一個broker可以儲存多個topic的queue,broker與topic是多對多的關係。
NameServer
輕量級命名服務,producer、consumer和broker的路由控制中心,提供類似於服務註冊與發現功能,通常以叢集形式部署,彼此之間無通訊,區域性出問題不影響整個叢集,所以穩定性很高。
每個NameServer維護著叢集中所有的broker及topic路由資訊。
Topic
訊息主題,一級訊息型別,通過 topic 對訊息進行分類與業務隔離。如:交易成功訊息和使用者註冊訊息可以通過不同topic進行區分。
topic是一個邏輯概念,一個topic可以劃分為多個queue,這些queue儲存在不同的broker中,broker與topic是多對多的關係。
如果訊息量比較大的情況下,應該多指定幾個佇列以便分散broker和consumer的壓力。
Tag
訊息標籤,二級訊息型別,用來進一步區分某個topic下的訊息分類,如用success、refund分別表示交易成功和退款的訂單訊息。
消費者可以通過訂閱不同的tags來對topic下的訊息進行選擇性的消費。
Message
訊息,傳送、儲存和消費的載體,一條訊息必須指定topic和訊息體(body),另外可以選擇性指定tags和keys。
Queue
訊息佇列,由同一型別的訊息按傳送順序組成,broker中劃分儲存的最小單元,topic與queue的關係為一對多。
同一類message順序組成queue,一個或多個queue組成topic,topic按queue維度存放在不同的broker中。
實際上queue儲存的不是真正的訊息資料,而是指向commit log的訊息索引,commit log才是儲存訊息的結構。
Broker、Topic與Queue的關係
建立topic時可以用叢集模式建立,每個broker中的queue數量相同;也可以用單個broker模式建立,這樣每個broker中的queue數量可能不同。它們之間的具體關係(單個broker模式建立topic)如下圖:
ClientId (即ConsumerId)
代表消費者、傳送者啟動的客戶端id,MQClientInstance是根據clientId來生成單例的,也就是如果相同的clientId只會在第一次啟動生產者或者消費者時,生成MQClientInstance。
低版本時,一個jvm啟動多個消費者、或者啟動多個生產者,clientId是相同的,也就是共用MQClientInstance,就會有問題,後面部落格會討論。
這個clientId在叢集負載均衡模式下有作用,負載均衡是按照group、topic(消費佇列)來分配到各個消費者clientId(consumerId)的。
二、叢集架構
叢集部署結構
啟動順序:1、NameServer啟動 → 2、Broker啟動 → 3、Broker建立topic → 4、Producer啟動 → 5、Consumer啟動
一般建議先啟動消費者,再啟動生產者;
通訊方式
縱軸表示通訊發起方,橫軸表示被連線方
NameServer | Broker | Producer | Consumer | |
NameServer | 彼此無通訊 | 每隔10s掃描所有存活的broker,若2分鐘內沒有收到心跳包,則斷開與broker的連線,並更新topic與queue的關係 | - | - |
Broker | 每個broker與所有NameServer保持長連線,每隔30s向所有NameServer傳送包含了自身topic配置資訊的心跳包;包含資訊:地址,brokerName,brokerId,topic,queue等 | 彼此無通訊 | 每隔10s掃描所有存活的producer,若2分鐘內沒有收到心跳資料,則斷開與producer的連線 | 每隔10s掃描所有存活的consumer,若2分鐘內沒有收到心跳資料,則斷開與consumer的連線,並向該消費者組所有消費者發出通知,重新分配佇列進行消費 |
Producer | 每個producer與一臺NameServer保持長連線,每隔30s查詢topic配置資訊;如果連線的NameServer宕機,則會自動連線下一個NameServer | 每個producer和(topic的queue)關聯的所有broker保持長連線,每隔30s傳送心跳 | 彼此無通訊 | 彼此無通訊 |
Consumer | 每個consumer與一臺NameServer保持長連線,每隔30s查詢topic配置資訊;如果連線的NameServer宕機,則會自動連線下一個NameServer | 每個consumer和(topic的queue)關聯的所有broker保持長連線,每隔30s傳送心跳 | 彼此無通訊 | 彼此無通訊 |
叢集部署模式
單Master:配置簡單,安全性低,一般不用於生產環境
多Master:效能較高,但無法做到高可用,較少採用
主從同步雙寫:主從節點都寫入成功後才向客戶端返回成功;一致性和安全性高但效能稍差;公司叢集採用該方式,2主2從共4個節點
主從非同步複製:Master寫入成功立即返回,Slave非同步方式複製訊息;效能較高但有資料丟失風險
持久化方式
同步刷盤:刷盤到檔案才會返回成功
非同步刷盤:先返回,再重新整理到磁碟;公司叢集採用該方式
三、支援特性
訊息傳送方式
同步傳送:傳送執行緒等待發送結果或超時;適用於絕大部分訊息較為重要的業務場景
非同步傳送:呼叫傳送介面後不等待發送結果,繼續執行後續業務邏輯,提供傳送回撥介面(SendCallback);適用於訊息重要但又對傳送效率要求較高的場景
單向傳送:只發送,不關心傳送結果;適用於併發量大,訊息重要性不高的場景
訊息獲取方式
push模式:(看起來是)broker將訊息推送給consumer,最常用模式
優點:訊息處理及時,客戶端邏輯簡單
缺點:訊息存放在消費者記憶體中,可能導致消費者的訊息積壓,處理緩慢
適用場景:對於資料實時性要求高的場景
pull模式:consumer主動從broker拉取訊息
優點:客戶端可以根據自己的消費能力進行消費,不會導致消費者訊息積壓
缺點:應用程式邏輯稍複雜,需要記錄佇列的消費位置及拉取頻率等;拉取頻率高容易導致服務端壓力大,頻率低訊息得不得及時消費
適用場景:生產者訊息數量大,消費邏輯複雜或消費能力較低的場景
訊息過濾
TAG模式:常用的訊息過濾模式,傳送階段在構建訊息時指定TAG,consumer訂閱時可以訂閱多個TAG或模糊匹配
SQL表示式:通過設定訊息的使用者屬性,過濾時執行SQL過濾表示式進行條件匹配。注意:預設不支援屬性過濾,要開啟該功能需要在broker的配置檔案中新增enablePropertyFilter = true並全部重啟後生效
類過濾模式:自定義訊息過濾介面(MessageFilter)實現訊息過濾
其中後兩種方式只支援push方式。
訊息模式
叢集模式:通常同一個queue由consumer group中的固定consumer例項消費,但也有例外,如pull模式下拉取全部佇列進行消費;適用於大部分場景。
廣播模式:每個consumer例項都會消費topic中的全部訊息;應用場景舉例:訂單服務中,節點本地記憶體儲存了使用者的新老使用者狀態,當新使用者變為老使用者時,需要通知所有節點更新本地狀態。
事務訊息
支援先發送半訊息到broker,此時訊息無法被consumer消費,待producer本地事務完成後再通知broker該訊息可以被正常傳送。
注意事務訊息與分散式事務的區別,前者指傳送訊息和本地事務的執行結果保持一致(本地事務執行完成則傳送成功,本地事務執行失敗則回滾傳送的訊息),後者指不同分散式節點之間的執行結果保持一致。
應用場景舉例:下單成功才向用戶推送訂單訊息。
順序訊息
指同一型別(topic)中具有先後順序的訊息,可以保證消費時的順序與傳送時保持一致。如:下單→付款→發貨。
順序訊息分為全域性有序和區域性有序,全域性有序需要設定佇列數為1才能保證,這會大大降低系統吞吐量,一般應用實現區域性有序就能滿足要求。
實現關鍵:有序傳送,有序儲存,有序消費,缺一不可
有序傳送:由同一個producer單執行緒按產生順序傳送
有序儲存:按照一定的規則選取同一個佇列傳送,如按照訂單號取模確定傳送的訊息佇列
有序消費:一個消費者單執行緒消費,保證了FIFO
延遲訊息
延遲訊息是指傳送出去的訊息不能馬上被消費,而是要等待某些固定的時間後才會投遞給真正的佇列進行消費。Apache版本支援18種特定時間延遲,阿里收費版支援精確到秒級的延遲。
實現思想是broker為每種延遲時間的訊息建立一個佇列,該佇列對正常的消費者不可見,然後啟動執行緒輪詢這些佇列,如果有訊息達到延遲時間,就將其轉為普通訊息存放到真實的topic佇列下。
應用場景舉例:使用者下單半小時後提醒其支付
思考:如何實現支援任意時間的延遲?
訊息重試與死信佇列
訊息因為各種原因消費失敗後,會被重新投遞到名為%RETRY%+${consumerGroup}的重試佇列(注意:該佇列以consumerGroup為維度而不是topic),並且每次投遞根據重試次數設定延遲級別。
當重試次數達到一定限制後(預設16次)會成為死信訊息(DLM:Dead-Letter Message),死信訊息不會被立刻丟棄,而是存放在專門的佇列中,存放死信訊息的佇列就叫死信佇列(DLQ:Dead-Letter Queue)。
進入死信佇列的訊息需要人工干預,通常有三種處理方式:
1、直接丟棄
2、將死信訊息重新投遞到正常的訊息佇列中
3、建立專門處理死信佇列的consumer進行消費
思考:
為什麼要設計重試佇列和死信佇列?
延遲訊息與消費重試的關係?
轉載:https://blog.csdn.net/wp120453/article/details/111674222
TRANSLATE with x English TRANSLATE with EMBED THE SNIPPET BELOW IN YOUR SITE Enable collaborative features and customize widget: Bing Webmaster Portal Back 此頁面的語言為中文(簡體) 翻譯為
- 中文(簡體)
- 中文(繁體)
- 丹麥語
- 烏克蘭語
- 烏爾都語
- 亞美尼亞語
- 俄語
- 保加利亞語
- 克羅埃西亞語
- 冰島語
- 加泰羅尼亞語
- 匈牙利語
- 卡納達語
- 印地語
- 印尼語
- 古吉拉特語
- 哈薩克語
- 土耳其語
- 威爾士語
- 孟加拉語
- 尼泊爾語
- 布林語(南非荷蘭語)
- 希伯來語
- 希臘語
- 庫爾德語
- 德語
- 義大利語
- 拉脫維亞語
- 挪威語
- 捷克語
- 斯洛伐克語
- 斯洛維尼亞語
- 旁遮普語
- 日語
- 普什圖語
- 毛利語
- 法語
- 波蘭語
- 波斯語
- 泰盧固語
- 泰米爾語
- 泰語
- 海地克里奧爾語
- 愛沙尼亞語
- 瑞典語
- 立陶宛語
- 緬甸語
- 羅馬尼亞語
- 寮國語
- 芬蘭語
- 英語
- 荷蘭語
- 薩摩亞語
- 葡萄牙語
- 西班牙語
- 越南語
- 亞塞拜然語
- 阿姆哈拉語
- 阿爾巴尼亞語
- 阿拉伯語
- 韓語
- 馬爾加什語
- 馬拉地語
- 馬拉雅拉姆語
- 馬來語
- 馬耳他語
- 高棉語