Apache RocketMQ調研

1、發展歷程

早期淘寶內部有兩套消息中間件系統:Notify和Napoli。 先有的Notify(至今12歷史),後來因有序場景需求,且剛好當時Kafka開源(2011年),因此參照Kafka的設計理念自研了RocketMQ。 目前Notify和RocketMQ兩者的定位以下:html

  • RocketQ 主要面向消息有序的場景,可以提供更大的消息堆積能力,拉模式,消息持久化在磁盤
  • Notify主要面向更加安全可靠地交易類場景,無序、推模式、消息持久化在mysql

RocketMQ發展歷程以下java

  • Metaq 1.x 開源社區維護killme2008維護,由於依賴zk掛了,致使上下游服務全網宕機,到了12年基於開源Kafka,直接用java語言翻譯重寫
  • Metaq 2.x 2012年11月上線,淘寶內部使用
  • RocketMQ 3.x 後來一統江湖成爲整個阿里系主流MQ。基於公司內部開源共建原則, RocketMQ項目只維護核心功能,且去除了全部其餘運行時依賴,核心功能最簡化。每一個BU的個性化需求都在RocketMQ項目之上進行深度定製。RocketMQ向其餘BU提供的僅僅是Jar包,例如要定製一個Broker,那麼只須要依賴rocketmq-broker這個jar包便可,可經過API進行交互,若是定製client,則依賴rocketmq-client這個jar包,對其提供的api進行再封裝。
  • RocketMQ 4.x.x 捐獻給Apache社區,通過一年時間重構孵化成爲頂級項目

Metaq更名爲RocketMQ,RocketMQ項目作核心功能,淘寶內部其餘個性化需求有作定製化開發,如:
com.taobao.metaq v3.0 (爲淘寶應用提供消息服務 ) com.alipay.zpullmsg v1.0 (爲支付寶應用提供消息服務) com.alibaba.commonmq v1.0 (爲 B2B 應用提供消息服務)mysql

 

RocketMQ一共經歷了三代里程碑演進:sql

  • Notify 爲阿里系第一代MQ產品。推模式,數據存儲採用關係型數據庫。
  • Metaq 爲阿里系第二代MQ產品。拉模式,自研的專有消息存儲,在日誌處理方面參考Kafka,典型表明MetaQ。
  • RocketMQ爲阿里系第三代MQ產品。以拉模式爲主,兼有推模式,低延遲消息引擎RocketMQ,在二代功能特性的基礎上,爲電商金融領域添加了可靠重試、基於文件存儲的分佈式事務等特性。使用在了阿里大量的應用上,典型如雙11場景,具備萬億級消息堆積能力。

RocketMQ項目根據開源與商業分紅2個版本:docker

  • Apache RocketMQ開源版
  • 2013年,阿里雲ONS(功能相比較更齊全,特別是運維體系完善,例如:運維管控,安全受權,深度培訓等歸入商業重中之重)
  • 2015年,Aliware MQ(Message Queue)是RocketMQ的商業版本,是阿里雲商用的專業消息中間件,是企業級互聯網架構的核心產品,基於高可用分佈式集羣技術,搭建了包括髮布訂閱、消息軌跡、資源統計、定時(延時)、監控報警等一套完整的消息雲服務。

RocketMQ項目根據開源與商業分紅2個版本:數據庫

  • Apache RocketMQ是對外開源版
  • 2013年,阿里雲ONS(功能相比較更齊全,特別是運維體系完善,例如:運維管控,安全受權,深度培訓等歸入商業重中之重)
  • 2015年,Aliware MQ(Message Queue)是RocketMQ的商業版本,是阿里雲商用的專業消息中間件,是企業級互聯網架構的核心產品,基於高可用分佈式集羣技術,搭建了包括髮布訂閱、消息軌跡、資源統計、定時(延時)、監控報警等一套完整的消息雲服務。

2、系統架構

 系統定位

  • 是一個隊列模型的消息中間件,具備高性能、高可靠、高實時、分佈式特色
  • 同時支持Push與Pull方式消費消息
  • 能支撐天貓雙十一海量消息考驗
  • 可以保證嚴格的消息順序
  • 提供豐富的消息拉取模式
  • 高效的訂閱者水平擴展能力
  • 億級消息堆積能力

四種集羣部署方式: 

  • 單master (缺點:broker宕機,服務不可用)
  • 多master無slave (缺點:單臺機器宕機期間,這臺機器上未被消費的消息在機器恢復以前不可訂閱)
  • 多master多slave,異步複製 (缺點:Master 宕機,磁盤損壞狀況,可能會丟失少許消息)
  • 多master多slave,同步雙寫(缺點:性能比異步複製模式略低,大約低 10%左右)

生產環境部署都是多主多從。下面以2主2從爲例api

 

組件角色 

  • Producer:消息發佈的角色,支持分佈式集羣方式部署。與NameServer(隨機)中的其中一個節點創建長連接,按期獲取Topic路由信息,並向提供Topic服務的Master創建長連接,另外和 Master之間作心跳。Producer經過MQ的負載均衡模塊選擇相應的Broker集羣隊列進行消息投遞,投遞的過程支持快速失敗而且低延遲。 
  • Consumer:消息消費的角色,支持分佈式集羣方式部署。與NameServer(隨機)中的其中一個節點創建長連接,按期獲取Topic路由信息,並向提供topic服務的Master、Slave創建長鏈接 ,由Broker配置訂閱規則。支持以push推,pull拉兩種模式對消息進行消費。同時也支持集羣方式和廣播方式的消費,它提供實時消息訂閱機制,能夠知足大多數用戶的需求。
  • NameServer:NameServer是一個很是簡單的Topic路由註冊中心,其角色相似Dubbo中的zookeeper,支持Broker的動態註冊與發現。主要包括兩個功能:Broker管理,NameServer接受Broker集羣的註冊信息而且保存下來做爲路由信息的基本數據。而後提供心跳檢測機制,檢查Broker是否還存活;路由信息管理,每一個NameServer將保存關於Broker集羣的整個路由信息和用於客戶端查詢的隊列信息。而後Producer和Conumser經過NameServer就能夠知道整個Broker集羣的路由信息,從而進行消息的投遞和消費。NameServer一般也是集羣的方式部署,各實例間相互不進行信息通信。Broker是向每一臺NameServer註冊本身的路由信息,因此每個NameServer實例上面都保存一份完整的路由信息。當某個NameServer因某種緣由下線了,Broker仍然能夠向其它NameServer同步其路由信息,Producer,Consumer仍然能夠動態感知Broker的路由的信息。
  • BrokerServer:Broker主要負責消息的存儲、投遞和查詢以及服務高可用保證,爲了實現這些功能,Broker包含了如下5個重要子模塊:安全

    • Remoting Module:整個Broker的實體,負責處理來自clients端的請求。
    • Client Manager:負責管理客戶端(Producer/Consumer)和維護Consumer的Topic訂閱信息
    • Store Service:提供方便簡單的API接口處理消息存儲到物理硬盤和查詢功能。
    • HA Service:高可用服務,提供Master Broker 和 Slave Broker之間的數據同步功能。
    • Index Service:根據特定的Message key對投遞到Broker的消息進行索引服務,以提供消息的快速查詢。

3、關鍵特性

  1.單機支持1萬以上持久化隊列服務器

  • 順序寫,隨機讀。 consumerQueue是邏輯隊列存儲元數據信息,commitlog負責存儲消息,consumerQueue只存儲消息在commitlog中的位置信息,定長存儲,支持串行方式刷盤。

  2.刷盤策略數據結構

  • 同步刷盤
  • 異步刷盤

  兩者的區別在因而寫完PageCache直接返回,仍是刷盤後返回

  3.消息查詢/消息回溯

  • 支持MessageID和MessageKey查詢。(業務場景:如某個訂單處理失敗,是消息沒收到仍是收處處理出錯了)
  • 按照時間來回溯消息,精度毫秒。(業務場景:訂單分析,程序bug,致使今天從某個時間點的消息須要從新開始消費)

  4.消息過濾

  • Broker端(tag的哈希值比對,丟到對應的consumeQueue中) consumer端(直接和tag比)

  5.消息獲取機制

  本質上都是Pull機制(據官方資料顯示其中PushConsumer的實時性接近於push)。

  • PushConsumer: consumer經過長輪詢拉取消息後回調MessageListener接口完成消費,業務只須要完成MessageListener完成業務邏輯便可。(註冊監聽回調,一個線程專門長輪訓從broker端拉消息,push到一個本地可配置隊列)輯便可。(註冊監聽回調,一個線程專門長輪訓從broker端拉消息,push到一個本地可配置隊列) 
  • PullConsumer: 徹底由業務系統去控制,定時拉取消息,指定隊列消費,主要由業務控制。

  6.單隊列並行消費

  • 單隊列一批消息拉取到消費端,既能夠支持單線程串行有序消費,也能夠支持多線程亂序消費提升併發性能,以下圖所示:

 

  採用滑動窗口方式並行消費,多個線程消費,提交offset都是最小offset。

  7.消費負載均衡

都在客戶端實現
Producer端:從NameServer獲取MessageQueue列表,RR選擇具體的消息隊列發送消息。

 

  Consumer端: 從NameServer獲取MessageQueue列表和其餘Consumer狀態信息,達到平均消費目的(consumer超過隊列數則處於空閒狀態)

  

   8.順序消息原理

 在RocketMQ中,主要指的是局部順序,即一類消息爲知足順序性,必須 Producer 單線程順序發送,且發送到同一個隊列,這樣 Consumer 就能夠按照 Producer 發送 的順序去消費消息。

  • 普通順序消息:Broker重啓,隊列總數發生變化,致使哈希取模後定位隊列變化,致使短暫消息順序不一致。
  • 嚴格順序消息:只要一臺機器不可用,整個集羣不可用。(同步雙寫保證)

   

  9.事務支持
  RocketMQ採用了2PC的方案來提交事務消息,同時增長一個補償邏輯來處理二階段超時或者失敗的消息,以下圖所示:

   

  上圖說明了事務消息的大體方案,分爲兩個邏輯:正常事務消息的發送及提交、事務消息的補償流程
  事務消息發送及提交:

  1. 發送消息(half消息)
  2. 服務端響應消息寫入結果
  3. 根據發送結果執行本地事務(若是寫入失敗,此時half消息對業務不可見,本地邏輯不執行)
  4. 根據本地事務狀態執行Commit或者Rollback(Commit操做生成消息索引,消息對消費者可見)

  補償流程:

  1. 對沒有Commit/Rollback的事務消息(pending狀態的消息),從服務端發起一次「回查」
  2. Producer收到回查消息,檢查回查消息對應的本地事務的狀態
  3. 根據本地事務狀態,從新Commit或者Rollback
  4. 補償階段用於解決消息Commit或者Rollback發生超時或者失敗的狀況。

  10.延時消息
  業務場景:支付曾經提過延時消費需求(對應消費失敗後,延時多久再推送)
  開源版本RocketMQ僅支持定時Level(幾個梯度的延時,5s、10s、1min等) 阿里雲的ONS支持定時level,以及制定毫秒級別延時時間

  11.消息失敗重試

  • Producer端:

      Producer 的 send 方法自己支持內部重試,重試邏輯以下:
  (1) 至多重試 3 次
  (2) 若是發送失敗,則輪轉到下一個 Broker
  (3) 這個方法的總耗時時間不超過 sendMsgTimeout設置的值,默認 10s因此,若是自己向 broker 發送消息產生超時異常,就不會再作重試。 再發送失敗由應用層本身作。

  • Consumer端:
    廣播模式:發送失敗的消息丟棄, 廣播模式對於失敗重試代價太高,對整個集羣性能會有較大影響,失敗重試功能交由應用處理 集羣模式:將消費失敗的消息一條條的發送到broker的重試隊列中去,若是此時依然有發送到重試隊列仍是失敗的消息,那就在cosumer的本地線 程
    定時5秒鐘之後重試從新消費消息,再走一次上面的消費流程。

  12.Broker HA機制

  • 同步雙寫:HA 採用同步雙寫方式,主備都寫成功,嚮應用返回成功。
  • 異步複製:slave啓動一個線程,不斷從master拉取commitlog中的數據,而後異步build出ConsumeQueue數據結構。

  13.死信隊列
  因爲某些緣由消息沒法被正確的投遞,爲了確保消息不會被無端的丟棄,通常將其置於一個特殊角色的隊列,這個隊列通常稱之爲死信隊列。與此對應的還有一個「回退隊列」的概念,試想若是消費者在消費時發生了異常,那麼就不會對這一次消費進行確認(Ack), 進而發生回滾消息的操做以後消息始終會放在隊列的頂部,而後不斷被處理和回滾,致使隊列陷入死循環。爲了解決這個問題,能夠爲每一個隊列設置一個回退隊列,它和死信隊列都是爲異常的處理提供的一種機制保障。實際狀況下,回退隊列的角色能夠由死信隊列和重試隊列來扮演。


  14.重試隊列
  重試隊列其實能夠當作是一種回退隊列,具體指消費端消費消息失敗時,爲防止消息無端丟失而從新將消息回滾到 Broker 中。與回退隊列不一樣的是重試隊列通常分紅多個重試等級,每一個重試等級通常也會設置從新投遞延時,重試次數越多投遞延時就越大。舉個例子:消息第一次消費失敗入重試隊列 Q1,Q1 的從新投遞延遲爲 5s,在 5s 事後從新投遞該消息;若是消息再次消費失敗則入重試隊列 Q2,Q2 的從新投遞延遲爲 10s,在 10s 事後再次投遞該消息。以此類推,重試越屢次從新投遞的時間就越久,爲此須要設置一個上限,超過投遞次數就入死信隊列。重試隊列與延遲隊列有相同的地方,都是須要設置延遲級別,它們彼此的區別是:延遲隊列動做由內部觸發,重試隊列動做由外部消費端觸發;延遲隊列做用一次,而重試隊列的做用範圍會向後傳遞。

4、不足之處 

  RocketMQ無論系統架構,仍是底層存儲都有居多亮點,以此來支撐強大的各類特性,不能否認也有居多不足之處:

  • 不支持Master/Slave自動切換。RocketMQ開源版本目前還不支持把Slave自動轉成Master,若是機器資源不足,須要把Slave轉成Master,則要手動中止Slave角色的Broker,更改配置文件,用新的配置文件啓動Broker。商業版本支持自動master/slave主從切換
  • 不支持數據遷移,對服務擴容不太友好,也不靈活。若是服務須要擴容,只能增長服務器節點數了,而後新增queue分配到新節點上。若是新老機器負載不均衡,要麼多增長queue到新機器上,要麼替換性能不強的老舊機器
  • 不支持多掛載點。當今硬件發展突飛猛進,pc服務器性能愈來愈強大,一個物理機器會掛載很塊多磁盤,但一個RocketMQ實例卻只能讀寫操做一個掛載點數據,想榨乾機器資源,操做多掛載點須要部署多實例或依靠docker容器等來實現

 

博客地址引用:http://www.javashuo.com/article/p-zxhfrkhi-dw.html

相關文章
相關標籤/搜索