RocketMQ源碼分析之基礎知識介紹(一)

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 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, 如果沒有消費一定不會ack

  • Exactly 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網絡部署圖
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邏輯部署結構
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數據結構
    Procuder數據結構

    Producer數據結構

  • Consumer數據結構
    在Producer端,使用org.apache.rocketmq.common.message.Message這個數據結構,由於Broker會爲Message增加數據結構,所以消息到達Consumer後, 會在Message基礎上增加多個字段,Consumer看到的是org.apache.rocketmq.common.message.MessageExt 這個數據結構,MessageExt繼承自Message 。

注: 後期有什麼新的內容會不定期的更新

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章