RocketMQ之基礎知識講解
一、RocketMQ知識介紹
1.1 前言
- RocketMQ是一個隊列模型的消息中間件,具有高性能、高可用、高實時、分佈式特點。
- 對列集合成爲Topic, 如果Consumer做廣播消費,則一個Consumer實例消費這個Topic對應的所有隊列;如果做集羣消費,則多個Consumer實例平均這個Topic對應的隊列集合。
- 能夠保證嚴格的消息順序, 但是會失去FailOver特性,可以通過同步雙寫模式解決,但是服務切換任然會造成幾分鐘服務不可用。
- 可以提供多種消息拉取方式
- 高效的訂閱者水平擴展能力
- 實時的消息訂閱能力
- 億級消息堆積能力,RocketMQ消息是持久化的,內部通過將幾天前的消息刪除,來滿足億級消息的處理能力。
- 較少的依賴
RocketMQ主要引用了JMS規範和Corbar Notification規範, 但是RocketMQ並不遵循任何規範,它參考了各種規範和同類的設計思想 。
RocketMq經歷了三個主要版本的迭代,Metaq 1.x , MetaQ 2.x , RocketMQ 3.x , 在 Metaq 1.x 和 2.x版本中,用zookeeper作爲註冊中心,以滿足高可用性能,但是nameSrv不僅可以滿足高可用,相較於zookeeper更加的輕量級而且性能更好
1.2 專業術語
- Producer
消息生產者,負責產生消息,一般由業務系統負責產生消息 - Consumer
消息消費者,負責消費消息,一般是後臺系統負責異步消費 - Push Consumer
Consumer的一種, 應用通常向Consumer註冊一個Listener接口, 一旦收到消息, Consumer對象立即回掉Listener接口方法 。 - Pull Consumer
Cosumer的一種, 應用通常主動調用Consumer拉取消息方法從Broker拉取消息, 主動權由應用控制 - Producer Group
一類Producer的集合名稱,這類Producer通常發送一類消息, 且發送邏輯一樣 - Consumer Group
一類Consumer的集合名稱, 這類Consumer通常消費一類消息,且消費邏輯一樣 - Broker
消息中轉角色, 負責存儲消息,轉發消息,一般也成爲Server, 在JMS規範中成爲Provider - 廣播消費
一條消息被多個Consumer消費, 即使這些Consumer屬於同一個Consumer Group , 消息也會被Consumer Group中的每一個Consumer都消費一次,廣播消費中的Consumer Group 概念可以認爲在消息劃分方面沒有意義。
在Corba Notification規範中,消息方式都屬於廣播消費。
在JMS規範中,相當於JMS publish/subscribe 模式 - 集羣消費
一個Consumer Group中的Consumer實例平均分攤消費消息,其中Consumer Group有三個實例 ,那麼每個實例只需要消費其中3條消息。
在JMS規範中,point-to-point與之類似,但是RocketMQ的集羣消費能力 >= PTP模型,因爲單個Consumer Group內的消費者類似於PTP,但是一個Topic/Queue可以被多個Consumer Group消費。 - 普通順序消息
正常情況下,可以保證完全的順序消費,但是一旦發生通信異常,Broker重啓,由於隊列總數發生變化,哈希 取模後定位的隊列會變化,產生短暫的消息順序不一致。如果能夠忍受消息的短暫亂序可以使用普通順序方式 - 嚴格順序消息
無論正常情況還是異常情況,都可以保證完全的順序消費,但是犧牲了分佈式Failover特性,即只要Broker集羣中有一臺機器不可用,則整個集羣不可用,服務可用性大大降低,如果服務器部署爲同步雙寫模式,此缺陷可通過備機切換爲主機避免,不過仍然存在幾分鐘的服務不可用(依賴同步雙寫,主備自動切換,主備切換功能目前還沒有實現) - Message Queue
在RocketMQ中,所有的消息隊列都是持久化,長度無限制的數據結構,所謂長度無限制是指隊列中的每個存儲單元都是定長的,訪問其中的存儲單元通過offset來訪問,offset爲java long類型,64位,理論上100年不會溢出,另外隊列只保存最近幾天的數據,之前的數據會按照過期時間來刪除。
1.3 RocketMQ解決的問題
- Publish/Subscribe(發佈訂閱) 支持
消息中間件最基本的功能 Message Priority(消息優先級) 不支持
消息優先級指的是在同一個隊列中每條消息有不同的優先級,按照消息優先級進行投遞。RocketMQ所有消息都是持久化的,同一個隊列消息如果按照優先級進行投遞,需要進行排序,開銷會很大。
替代方案, 設置多個隊列, 分別表示不同優先級的隊列
1) 達到優先級目的,但不是嚴格意義的優先級。用多個Topic分別表示不同的優先級, 需要對業務優先級的額精確的做出妥協 。
2) 嚴格意義的優先級,優先級用整數表示。這種方式不能通過不同的Topic來解決,如果通過MQ來解決這個問題,會對性能有很大影響, 需要確定是否確實需要這種嚴格的優先級, 如果通過多個Topic來表示優先級會有什麼影響 。- Message Order(消息有序) 支持
消息有序指的是一類消息消費時,能按照發送的順序來消費,比如果同一個訂單的不同階段可以保證完全有序 。
- Message Order(消息有序) 支持
Message Filter(消息過濾) 支持
1) Broker端消息過濾。按照Consumer端的要求進行過濾,減少了網絡無用消息的過濾,但是增加了Broker端的負擔,實現相對複雜 。
2) Consumer端消息過濾。可以由應用完全自定義實現,可能會造成很多無用的消息傳輸到Consumer端。Message Persistense(消息持久化) 支持
1) 持久化到數據庫, 比如Mysql
2) 持久化到KV存儲, 例如levelDB
3) 文件記錄是持久化
4) 對內存數據庫做一個持久化鏡像,比如beanstalkd, Visinotify
1),2),3) 具有將內存隊列Buffer進行擴展的能力 , 4) 是內存的鏡像,作用是當Broker掛掉或重啓後仍能將之前的數據回覆出來。Message Reliability(消息可靠性) 支持
影響消息可靠性的幾種情況,
1) RocketMQ可以保證消息不丟失或丟失少量數據。
Broker正常關閉, Broker異常crash, OS Crash, 機器斷電 但是可以立即回覆供電情況
2) 單點故障,一旦發生消息全部丟失。
機器無法開機, 磁盤設備損壞
解決方式: 通過異步複製, 可保證數據99%消息不丟失; 同步雙寫模式可以完全避免地點故障,但是會影響性能,適合對消息要求極高的場合 。Low Latency Messaging(低延遲消息) 支持
在消息不堆積情況下,消息到達Broker後,能立即到達Consumer。RockerMQ使用長輪詢Pull方式,可以保證消息非常實時 。At least Once(消息必須投遞一次) 支持
RocketMQ Consumer先Pull消息到本地,消費完後,才向客戶端ack, 如果沒有消費一定不會ackExactly Only Once 不支持
1) 發送消息階段, 不允許發送重複消息
2) 接收消息階段, 不允許消費重複消息
爲了支持高性能, RocketMQ不支持這種特性,在分佈式環境下,不可避免的會產生巨大的性能開銷,可以在業務上進行去重,保證消費消息的冪等性。消息堆積的處理方式
Broker的buffer通常指Broker中一個內存Buffer的大小,這類Buffer通常大小有限。RocketMQ沒有內存Buffer的概念, 數據是持久化到磁盤,定期進行數據清理。RocketMQ的內存Buffer抽象成一個無限的長度的隊列,理論不管來多少數據都可以容納的下,Broker會定期刪除過期的數據,以保證長度無限。回溯消費 支持
回溯是指已經消費Consumer已經消費成功,由於業務需求需要重新消費,RocketMQ支持按照時間回溯消費,時間維度精確到毫秒,可以向前回溯也可以向後回溯。消息堆積
消息中間件主要功能是異步解耦,還有個重要功能是擋住前端的數據洪峯,保證後端系統的穩定性,這要求消息中間件具有一定的消息堆積能力。處理方式
1) 消息堆積在內存Buffer, 可以按照一定的策略丟棄消息,消息堆積後,性能不會下降太大,內存中存儲數據的多少對影響對外提供訪問的處理能裏影響有限。
1.1) 拒絕新來的消息,
1.2) 按照特定策略丟棄已有信息
AnyOrder, FifoOrder, LifoOrder, PriorityOrder, DeadlineOrder
2) 消息堆積到持久化系統中,例如DB,KV系統,文件記錄形式。堆積能裏評估標準:
1) 消息的堆積能力
2) 消息堆積後,發消息的吞吐量是否收到影響
3) 消息堆積後,發消息的吞吐量大小,是否會受到堆積的影響
4) 消息堆積後,訪問磁盤的消息時,吞吐量的大小- 定時消息
定時消息是指消息發到Broker後,不能被Consumer消費,要到特定的時間點或者等待特定的時間後才能被消費。
Broker支持定時消息,定時不支持任意時間精度,只支持特定的level,比如5s, 10s , 1mins
1.4 RocketMQ網絡部署圖
- Name Server是一個幾乎無狀態幾點, 可集羣部署,幾點之間無任何消息同步 。
- Broker分爲Master和Slave, 一個Master可以對應多個Slave,但是一個Slave只能對應一個Master, Master與Slave之間通過執行相同的Broker Name 不同的BrokerId來定義,brokerId = 0 表示Master節點, brokerId > 0 表示slave節點 , 每個broker與每個Name Server建立長連接,定時註冊Topic信息到Name Server
- Producer 與Name Server 集羣中的某個節點建立長連接(隨機選擇) , 定期從Namer Server獲取Topic的路由信息, 並向提供topic服務的Master建立長連接,且定時向Master發送心跳,Producer是無狀態的, 可集羣部署
- Consumer與Name Server集羣中的某個節點建立長連接(隨機選擇),定期從Name Server 獲取Topic的路由信息, 並向提供服務的Master、slave建立長連接,且定時向Master、Slave發送心跳,Consumer既可以向Master訂閱信息, 也可以向Slave訂閱信息,具體的訂閱規則由Broker的配置決定。
1.5 RocketMQ邏輯部署結構
Producer Group
- 用來表示發送消息用 , 一個Producer Group 包含多個Producer實例
- Producer實例可以是多臺機器,也可以是一臺機器的多個線程,或者一個線程的多個Producer對像
- 標識一類Producer
- 發送分佈式事務消息時,如果Producer中途意外宕機,Broker會主動回掉Producer Group 內的任意一臺機器來確認事務狀態
Consumer Group
- 用來表示一個消費者應用,一個Consumer Group 下包含多個Consumer實例
- Consumer實例,可以是多臺機器、一臺機器的多個線程、一個線程的多個Consumer對象
- 一個Consmer Group下多個Consumer以均攤的方式消費消息, 如果廣播的消費方式,那麼每個Consumer消費所有的消息
1.6 RocketMQ存儲特點 mmap + write方式
- 使用mmap + write 方式
- 優點:即使頻繁調用,小塊文件傳輸效率也很高
- 缺點: 不能很好的利用DMA方式, 迴避sendfile多消耗CPU,內存安全性控制複雜,需要比秒JVM Crash
使用sendfile方式
- 優點: 可以使用DMA方式,消耗CPU比較少, 大塊文件效率高,無內存安全問題
- 缺點:小塊文件傳輸效率較mmap方式低,只能是BIO方式傳輸,不能使用NIO。
數據存儲結構
圖片沒有導入成功, 後期導入可以導入再添加該部分信息RocketMQ關鍵特性
- 所有數據單獨存儲到一個Commit Log的位置信息,完全順序寫,隨機讀
- 對最終用戶展現的隊列實際只存儲消息在Commit Log的位置消息,並且串行方式刷盤
- 優點
- 隊列輕量化,單個隊列數量非常少。
- 對磁盤的訪問串行化,避免磁盤競爭,不會因爲隊列增加導致IOWAIT增高
- 缺點
- 寫雖然完全順序寫,但是讀卻變成了完全的隨機讀。
- 讀一條信息, 會先讀Consumer queue , 再讀Commit Log , 增加了開銷。
- 要保證Commit Log 與 Consume Queue完全的一致 , 增加了編程的複雜度
- 規避方式
- 隨機讀。儘可能讓讀命中PAGE CACHE,減少IO操作,多以內存越大越好。
- 如果系統中堆積的消息過多,讀數據要訪問磁盤會不會由於隨機讀導致系統性能急劇下降。 不會急劇下降
- 訪問PAGECACHE , 系統會提前預讀出更多的數據,在下次讀時, 可能命中內存 。
- 隨機訪問Commit Log 磁盤數據,設置系統IO調度算法位NOOP , 會在一定程度上將完全的隨機讀取變成順序跳躍方式 , 這種跳躍方式較隨機方式性能要快 。
- 由於Consume Queue存儲數據量極少,而且是順序讀,在PAGE CACHE預讀作用下,即使存在堆積,Consume Queue的讀性能幾乎和內存一致 。
- Commit Log中存儲了所有的元信息, 包含消息體 ,所以只要Commit Log 的消息在,Consume Queue即使數據丟失,任然可以回覆出來 。
- 數據刷盤
- 異步刷盤
- 同步刷盤
1.7RocketMQ客戶端
客戶端尋址方式
代碼中指定
producer.setNamesrvAddr("192.168.0.1:9876;192.168.0.2:9876"); consumer.setNamesrvAddr("192.168.0.1:9876;192.168.0.2:9876");
Java啓動參數中指定Name Server地址
-Drocketmq.namesrv.addr=192.168.0.1:9876;192.168.0.2:9876
環境變量指定Name Server地址
export NAMESRV_ADDR=192.168.0.1:9876;192.168.0.2:9876
- HTTP靜態服務器資源(推薦) 客戶端部署簡單, Name Server集羣可熱部署
客戶端啓動後, 會定時訪問一個靜態HTTP服務器,比如: http://jmenv.tbsite.net:8080/rocketmq/nsaddr
訪問後,這個地址會返回 192.168.0.1:9876;192.168.0.2:9876
可以通過修改/etc/host 增加如下配置 10.232.191.1 jmenv.tbsite.net
客戶端的公共配置
參數名 | 默認值 | 說明 |
---|---|---|
namesrvAddr | Name Server地址列表,多個Name Server用分號隔開 | |
clientIP | 本機IP | 客戶端本機IP, 多網卡的情況下,某些機器會發生無法識別客戶端IP地址的情況,需要應用在代碼強制指定 |
instanceName | DEFAULT | 客戶端實例名稱,客戶端創建多個Peoducer、Consumer實際是使用一個內部實例(這個實例包含網絡連接、線程資源等) |
clientCallbackExcutorThreads | 4 | 通信層異步回調線程數 |
poolNameServerInteval | 30000 | 淪輪詢Name Server 間隔時間,單位ms |
heartbeatInteval | 30000 | 向Broker發送心跳間隔時間 ,單位ms |
persistConsumerOffsetInteval | 5000 | 持久化Consumer消費進度間隔時間,得ms |
- Producer 配置
參數名 | 默認值 | 說明 |
---|---|---|
producerGroup | DEFAULT_PRODUCER | producer組名,多個Producer如果屬於一個應用,發送同樣的消息,則應該將他們歸爲一組 |
createTopicKey | TBW102 | 在發送消息時自動創建服務器不存在的topic,需要指定Key |
defaultTopicQueueNums | 4 | 默認創建的隊列數 |
sendMsgTimeOut | 10000 | 發送消息超時時間,單位毫秒(ms) |
compressMsgBodyOverHowmuch | 4096 | 消息body超過多大開始壓縮(Consumer收到消息會自動解壓縮),單位字節 |
retryAnotherBrokerWhenNotStoreOK | FALSE | 如果發送消息返回sendResult, 當是發送sendStatus != OK, 是否重試發送 |
maxMessageSize | 131072 | 客戶端限制的消息大小,超過報錯,同時服務端也會限制 |
transactionListener | 事務消息回查監聽器, 如果發送事務消息,必須設置 | |
checkThreadPoolMinSize | 1 | Broker回查Producer事務狀態時,線程池最小數目 |
checkThreadPoolMaxSize | 1 | Broker回查Producer事務狀態時, 線程池最大數目 |
checkRequestHoldMax | 2000 | Broker回查Producer事務狀態時, Producer本地緩衝請求隊列大小 |
- PushComsumer 配置
參數名 | 默認值 | 說明 |
---|---|---|
consumerGroup | DEFAULT_GROUP | Consumer組名,多個Consumer如果屬於一個應用,訂閱同樣的消息,且消費邏輯一樣,則應該將他們歸爲一組 |
messageModel | CLUSTERING | 消息模型 支持 1. 集羣消費 2. 廣播消費 |
consumerFromWhere | CONSUMER_FROM_LAST_OFFSET | Consumer啓動後默認從什麼位置開始消費 |
allocateMessageQueueStrategy | AllocateMessageQueueAveragely | Rebalance算法實現策略 |
subscription | {} | 訂閱關係 |
messageListener | 消息監聽器 | |
offsetStore | 消費進度存儲 | |
consumerThreadMin | 10 | 消費線程池最小數目 |
consumerThreadMax | 20 | 消費線程池最大數目 |
consumerConcurrentlyMaxSpan | 2000 | 單隊列並行消費允許的最大跨度 |
pullThresholdForQueue | 1000 | 拉消息本地隊列緩存消息最大數 |
pullInteval | 0 | 拉消息間隔,由於是長輪詢,所以爲0 ,但是應用爲了控流,也可以設置大於0的值,單位毫秒(ms) |
consumerMessageBatchMaxSize | 1 | 批量消費,一次消費多少條消息 |
ppullBatchSize | 32 | 批量拉消息, 一次最多拉多少條 |
- PullConsumer配置
參數名 | 默認值 | 說明 |
---|---|---|
producerGroup | DEFAULT_PRODUCER | producer組名,多個Producer如果屬於一個應用,發送同樣的消息,則應該將他們歸爲一組 |
brokerSuspendMaxTimeMills | 20000 | 長輪詢,Consumer拉消息請求在Broker掛起最長時間,單位毫秒(ms) |
cosumerTimeoutMillsWhenSuspend | 300000 | 長輪詢, Consumer拉消息請求在Broker掛起超過指定時間, 客戶端認爲超時,單位毫秒(ms) |
consumerPullTimeoutMills | 10000 | 非長輪詢,拉消息超時時間,單位毫秒(ms) |
messageModel | BROADCASTING | 消息模型,支持以下兩種, 1. 集羣消費 2.廣播消費 |
messageQueueListener | 監聽隊列變化 | |
offsetStore | 消息進度存儲 | |
registerTopics | [] | 註冊的Topic集合 |
allocateMessageQueueStrangely | AllocateMessageQueueAveragely | Rebalance算法實現策略 |
Producer數據結構
Producer數據結構 Consumer數據結構
在Producer端,使用org.apache.rocketmq.common.message.Message這個數據結構,由於Broker會爲Message增加數據結構,所以消息到達Consumer後, 會在Message基礎上增加多個字段,Consumer看到的是org.apache.rocketmq.common.message.MessageExt 這個數據結構,MessageExt繼承自Message 。
注: 後期有什麼新的內容會不定期的更新