RocketMQ 介紹

前言

消息隊列在互聯網技術存儲方面使用如此廣泛,幾乎所有的後端技術面試官都要在消息隊列的使用和原理方面對小夥伴們進行360°的刁難。

作爲一個在互聯網公司面一次拿一次Offer的麪霸,打敗了無數競爭對手,每次都只能看到無數落寞的身影失望的離開,略感愧疚(請允許我使用一下誇張的修辭手法)。

於是在一個寂寞難耐的夜晚,我痛定思痛,決定開始寫《吊打面試官》系列,希望能幫助各位讀者以後面試勢如破竹,對面試官進行360°的反擊,吊打問你的面試官,讓一同面試的同僚瞠目結舌,瘋狂收割大廠Offer!

撈一下

消息隊列系列前面兩章分別講了消息隊列的基礎知識,還有比較常見的問題和常見分佈式事務解決方案,那麼在實際開發過程中,我們使用頻率比較高的消息隊列中間件有哪些呢?

帥丙我工作以來接觸的消息隊列中間件有RocketMQKafka自研,是的因爲我主要接觸的都是電商公司,相對而言業務體量還有場景來說都是他們比較適合,再加上杭州阿里系公司偏多,身邊同事或者公司老大基本都是阿里出來創業的,那在使用技術棧的時候阿里系的開源框架也就成了首選。

就算是自研的中間件多多少少也是借鑑RocketMQ、Kafka的優點自研的,那我後面兩章就分別簡單的介紹下兩者,他們分別在業務場景和大數據領域各自發光發熱。

那到底是道德的淪喪,還是人性的泯滅,讓我們跟着敖丙走進RocketMQ的內心世界。

正文

RocketMQ簡介

RocketMQ是一個純Java、分佈式、隊列模型的開源消息中間件,前身是MetaQ,是阿里參考Kafka特點研發的一個隊列模型的消息中間件,後開源給apache基金會成爲了apache的頂級開源項目,具有高性能、高可靠、高實時、分佈式特點。

 

我們再看下阿里給他取的名字哈:Rocket 火箭 阿里這是希望他上天呀,不過我覺得這個名字確實挺酷的。

我們先看看他最新的官網

 

回顧一下他的心路歷程

2007年:淘寶實施了“五彩石”項目,“五彩石”用於將交易系統從單機變成分佈式,也是在這個過程中產生了阿里巴巴第一代消息引擎——Notify。

2010年:阿里巴巴B2B部門基於ActiveMQ的5.1版本也開發了自己的一款消息引擎,稱爲Napoli,這款消息引擎在B2B裏面廣泛地被使用,不僅僅是在交易領域,在很多的後臺異步解耦等方面也得到了廣泛的應用。

2011年:業界出現了現在被很多大數據領域所推崇的Kafka消息引擎,阿里巴巴在研究了Kafka的整體機制和架構設計之後,基於Kafka的設計使用Java進行了完全重寫並推出了MetaQ 1.0版本,主要是用於解決順序消息和海量堆積的問題。

2012年:阿里巴巴開源其自研的第三代分佈式消息中間件——RocketMQ

經過幾年的技術打磨,阿里稱基於RocketMQ技術,目前雙十一當天消息容量可達到萬億級。

2016年11月:阿里將RocketMQ捐獻給Apache軟件基金會,正式成爲孵化項目。

阿里稱會將其打造成頂級項目。這是阿里邁出的一大步,因爲加入到開源軟件基金會需要經過評審方的考覈與觀察。

坦率而言,業界還對國人的代碼開源參與度仍保持着刻板印象;而Apache基金會中的342個項目中,暫時還只有Kylin、CarbonData、Eagle 、Dubbo和 RocketMQ 共計五個中國技術人主導的項目。

2017年2月20日:RocketMQ正式發佈4.0版本,專家稱新版本適用於電商領域,金融領域,大數據領域,兼有物聯網領域的編程模型。

以上就是RocketMQ的整體發展歷史,其實在阿里巴巴內部圍繞着RocketMQ內核打造了三款產品,分別是MetaQNotifyAliware MQ

這三者分別採用了不同的模型,MetaQ主要使用了拉模型,解決了順序消息和海量堆積問題;Notify主要使用了推模型,解決了事務消息;而云產品Aliware MQ則是提供了商業化的版本。

經歷多次雙11洗禮的英雄

在備戰2016年雙十一時,RocketMq團隊重點做了兩件事情,優化慢請求與統一存儲引擎。

  • 優化慢請求:這裏主要是解決在海量高併發場景下降低慢請求對整個集羣帶來的抖動,毛刺問題。這是一個極具挑戰的技術活,團隊同學經過長達1個多月的跟進調優,從雙十一的覆盤情況來看,99.996%的延遲落在了10ms以內,而99.6%的延遲在1ms以內。優化主要集中在RocketMQ存儲層算法優化、JVM與操作系統調優。更多的細節大家可以參考《萬億級數據洪峯下的分佈式消息引擎》。
  • 統一存儲引擎:主要解決的消息引擎的高可用,成本問題。在多代消息引擎共存的前提下,我們對Notify的存儲模塊進行了全面移植與替換。

RocketMQ天生爲金融互聯網領域而生,追求高可靠、高可用、高併發、低延遲,是一個阿里巴巴由內而外成功孕育的典範,除了阿里集團上千個應用外,根據我們不完全統計,國內至少有上百家單位、科研教育機構在使用。

RocketMQ在阿里集團也被廣泛應用在訂單,交易,充值,流計算,消息推送,日誌流式處理,binglog分發等場景。

他所擁有的功能

我們直接去GitHub上看Apache對他的描述可能會好點

 

是的功能完整到爆炸基本上開發完全夠用,什麼?看不懂專業詞彙的英文?

帥丙是暖男來的嘛,中文功能如下 ↓

  • 發佈/訂閱消息傳遞模型
  • 財務級交易消息
  • 各種跨語言客戶端,例如Java,C / C ++,Python,Go
  • 可插拔的傳輸協議,例如TCP,SSL,AIO
  • 內置的消息跟蹤功能,還支持開放式跟蹤
  • 多功能的大數據和流生態系統集成
  • 按時間或偏移量追溯消息
  • 可靠的FIFO和嚴格的有序消息傳遞在同一隊列中
  • 高效的推拉消費模型
  • 單個隊列中的百萬級消息累積容量
  • 多種消息傳遞協議,例如JMS和OpenMessaging
  • 靈活的分佈式橫向擴展部署架構
  • 快如閃電的批量消息交換系統
  • 各種消息過濾器機制,例如SQL和Tag
  • 用於隔離測試和雲隔離羣集的Docker映像
  • 功能豐富的管理儀表板,用於配置,指標和監視
  • 認證與授權

他的項目結構組成是怎麼樣子的?

GitHub地址:https://github.com/apache/rocketmq

 

他的核心模塊:

  • rocketmq-broker:接受生產者發來的消息並存儲(通過調用rocketmq-store),消費者從這裏取得消息
  • rocketmq-client:提供發送、接受消息的客戶端API。
  • rocketmq-namesrv:NameServer,類似於Zookeeper,這裏保存着消息的TopicName,隊列等運行時的元信息。
  • rocketmq-common:通用的一些類,方法,數據結構等。
  • rocketmq-remoting:基於Netty4的client/server + fastjson序列化 + 自定義二進制協議。
  • rocketmq-store:消息、索引存儲等。
  • rocketmq-filtersrv:消息過濾器Server,需要注意的是,要實現這種過濾,需要上傳代碼到MQ!(一般而言,我們利用Tag足以滿足大部分的過濾需求,如果更靈活更復雜的過濾需求,可以考慮filtersrv組件)。
  • rocketmq-tools:命令行工具。

他的架構組成,或者理解爲爲什麼他這麼快?這麼強?這麼厲害?

他主要有四大核心組成部分:NameServerBrokerProducer以及Consumer四部分。

 

Tip:我們可以看到RocketMQ啥都是集羣部署的,這是他吞吐量大高可用的原因之一,集羣的模式也很花哨,可以支持多master 模式、多master多slave異步複製模式、多 master多slave同步雙寫模式。

而且這個模式好像Kafka啊!(我這裏是廢話,本身就是阿里基於Kafka的很多特性研發的)。

分別介紹下各個集羣組成部分吧

NameServer:

主要負責對於源數據的管理,包括了對於Topic和路由信息的管理。

NameServer是一個功能齊全的服務器,其角色類似Dubbo中的Zookeeper,但NameServer與Zookeeper相比更輕量。主要是因爲每個NameServer節點互相之間是獨立的,沒有任何信息交互。

NameServer壓力不會太大,平時主要開銷是在維持心跳和提供Topic-Broker的關係數據。

但有一點需要注意,Broker向NameServer發心跳時, 會帶上當前自己所負責的所有Topic信息,如果Topic個數太多(萬級別),會導致一次心跳中,就Topic的數據就幾十M,網絡情況差的話, 網絡傳輸失敗,心跳失敗,導致NameServer誤認爲Broker心跳失敗。

NameServer 被設計成幾乎無狀態的,可以橫向擴展,節點之間相互之間無通信,通過部署多臺機器來標記自己是一個僞集羣。

每個 Broker 在啓動的時候會到 NameServer 註冊,Producer 在發送消息前會根據 Topic 到 NameServer 獲取到 Broker 的路由信息,Consumer 也會定時獲取 Topic 的路由信息。

所以從功能上看NameServer應該是和 ZooKeeper 差不多,據說 RocketMQ 的早期版本確實是使用的 ZooKeeper ,後來改爲了自己實現的 NameServer 。

我們看一下Dubbo中註冊中心的角色,是不是真的一毛一樣,師出同門相似點真的很多:

 

Producer

消息生產者,負責產生消息,一般由業務系統負責產生消息。

  • Producer由用戶進行分佈式部署,消息由Producer通過多種負載均衡模式發送到Broker集羣,發送低延時,支持快速失敗。

  • RocketMQ 提供了三種方式發送消息:同步、異步和單向

  • 同步發送:同步發送指消息發送方發出數據後會在收到接收方發回響應之後才發下一個數據包。一般用於重要通知消息,例如重要通知郵件、營銷短信。

  • 異步發送:異步發送指發送方發出數據後,不等接收方發回響應,接着發送下個數據包,一般用於可能鏈路耗時較長而對響應時間敏感的業務場景,例如用戶視頻上傳後通知啓動轉碼服務。

  • 單向發送:單向發送是指只負責發送消息而不等待服務器迴應且沒有回調函數觸發,適用於某些耗時非常短但對可靠性要求並不高的場景,例如日誌收集。

Broker

消息中轉角色,負責存儲消息,轉發消息。

  • Broker是具體提供業務的服務器,單個Broker節點與所有的NameServer節點保持長連接及心跳,並會定時將Topic信息註冊到NameServer,順帶一提底層的通信和連接都是基於Netty實現的。
  • Broker負責消息存儲,以Topic爲緯度支持輕量級的隊列,單機可以支撐上萬隊列規模,支持消息推拉模型。
  • 官網上有數據顯示:具有上億級消息堆積能力,同時可嚴格保證消息的有序性

Consumer

消息消費者,負責消費消息,一般是後臺系統負責異步消費。

  • Consumer也由用戶部署,支持PUSH和PULL兩種消費模式,支持集羣消費廣播消息,提供實時的消息訂閱機制

  • Pull:拉取型消費者(Pull Consumer)主動從消息服務器拉取信息,只要批量拉取到消息,用戶應用就會啓動消費過程,所以 Pull 稱爲主動消費型。

  • Push:推送型消費者(Push Consumer)封裝了消息的拉取、消費進度和其他的內部維護工作,將消息到達時執行的回調接口留給用戶應用程序來實現。所以 Push 稱爲被動消費類型,但從實現上看還是從消息服務器中拉取消息,不同於 Pull 的是 Push 首先要註冊消費監聽器,當監聽器處觸發後纔開始消費消息。

消息領域模型

 

Message

Message(消息)就是要傳輸的信息。

一條消息必須有一個主題(Topic),主題可以看做是你的信件要郵寄的地址。

一條消息也可以擁有一個可選的標籤(Tag)和額處的鍵值對,它們可以用於設置一個業務 Key 並在 Broker 上查找此消息以便在開發期間查找問題。

Topic

Topic(主題)可以看做消息的規類,它是消息的第一級類型。比如一個電商系統可以分爲:交易消息、物流消息等,一條消息必須有一個 Topic 。

Topic 與生產者和消費者的關係非常鬆散,一個 Topic 可以有0個、1個、多個生產者向其發送消息,一個生產者也可以同時向不同的 Topic 發送消息。

一個 Topic 也可以被 0個、1個、多個消費者訂閱。

Tag

Tag(標籤)可以看作子主題,它是消息的第二級類型,用於爲用戶提供額外的靈活性。使用標籤,同一業務模塊不同目的的消息就可以用相同 Topic 而不同的 Tag 來標識。比如交易消息又可以分爲:交易創建消息、交易完成消息等,一條消息可以沒有 Tag

標籤有助於保持您的代碼乾淨和連貫,並且還可以爲 RocketMQ 提供的查詢系統提供幫助。

Group

分組,一個組可以訂閱多個Topic。

分爲ProducerGroup,ConsumerGroup,代表某一類的生產者和消費者,一般來說同一個服務可以作爲Group,同一個Group一般來說發送和消費的消息都是一樣的

Queue

Kafka中叫Partition,每個Queue內部是有序的,在RocketMQ中分爲讀和寫兩種隊列,一般來說讀寫隊列數量一致,如果不一致就會出現很多問題。

Message Queue

Message Queue(消息隊列),主題被劃分爲一個或多個子主題,即消息隊列。

一個 Topic 下可以設置多個消息隊列,發送消息時執行該消息的 Topic ,RocketMQ 會輪詢該 Topic 下的所有隊列將消息發出去。

消息的物理管理單位。一個Topic下可以有多個Queue,Queue的引入使得消息的存儲可以分佈式集羣化,具有了水平擴展能力。

Offset

RocketMQ 中,所有消息隊列都是持久化,長度無限的數據結構,所謂長度無限是指隊列中的每個存儲單元都是定長,訪問其中的存儲單元使用Offset 來訪問,Offset 爲 java long 類型,64 位,理論上在 100年內不會溢出,所以認爲是長度無限。

也可以認爲 Message Queue 是一個長度無限的數組,Offset 就是下標。

消息消費模式

消息消費模式有兩種:Clustering(集羣消費)和Broadcasting(廣播消費)。

默認情況下就是集羣消費,該模式下一個消費者集羣共同消費一個主題的多個隊列,一個隊列只會被一個消費者消費,如果某個消費者掛掉,分組內其它消費者會接替掛掉的消費者繼續消費。

而廣播消費消息會發給消費者組中的每一個消費者進行消費。

Message Order

Message Order(消息順序)有兩種:Orderly(順序消費)和Concurrently(並行消費)。

順序消費表示消息消費的順序同生產者爲每個消息隊列發送的順序一致,所以如果正在處理全局順序是強制性的場景,需要確保使用的主題只有一個消息隊列。

並行消費不再保證消息順序,消費的最大並行數量受每個消費者客戶端指定的線程池限制。

一次完整的通信流程是怎樣的?

Producer 與 NameServer集羣中的其中一個節點(隨機選擇)建立長連接,定期從 NameServer 獲取 Topic 路由信息,並向提供 Topic 服務的 Broker Master 建立長連接,且定時向 Broker 發送心跳。

Producer 只能將消息發送到 Broker master,但是 Consumer 則不一樣,它同時和提供 Topic 服務的 Master 和 Slave建立長連接,既可以從 Broker Master 訂閱消息,也可以從 Broker Slave 訂閱消息。

具體如下圖:

 

我上面說過他跟Dubbo像不是我瞎說的,就連他的註冊過程都很像Dubbo的服務暴露過程。

是不是覺得很簡單,但是你同時也產生了好奇心,每一步是怎麼初始化啓動的呢?

帥丙呀就知道大家都是求知慾極強的人才,這不我都準備好了,我們一步步分析一下。

主要是人才羣裏的仔要求我寫出來。。。(文末有進羣方式)

NameService啓動流程

在org.apache.rocketmq.namesrv目錄下的NamesrvStartup這個啓動類基本上描述了他的啓動過程我們可以看一下代碼:

  • 第一步是初始化配置

  • 創建NamesrvController實例,並開啓兩個定時任務:

  • 每隔10s掃描一次Broker,移除處於不激活的Broker

  • 每隔10s打印一次KV配置。

  • 第三步註冊鉤子函數,啓動服務器並監聽Broker。

NameService還有很多東西的哈我這裏就介紹他的啓動流程,大家還可以去看看代碼,還是很有意思的,比如路由註冊會發送心跳包,還有心跳包的處理流程路由刪除路由發現等等。

Tip:本來我想貼很多源碼的,後面跟歪歪(Java3y)討論了很久做出了不貼的決定,大家理解過程爲主!我主要是做只是掃盲還有一些痛點分析嘛,深究還是得大家花時間,我要啥都介紹篇幅就不夠了。

Producer

鏈路很長涉及的細節也多,我就發一下鏈路圖。

 

Producer是消息發送方,那他怎麼發送的呢?

通過輪訓,Producer輪訓某個Topic下面的所有隊列實現發送方的負載均衡

 

Broker

Broker在RocketMQ中是進行處理Producer發送消息請求,Consumer消費消息的請求,並且進行消息的持久化,以及HA策略和服務端過濾,就是集羣中很重的工作都是交給了Broker進行處理。

Broker模塊是通過BrokerStartup進行啓動的,會實例化BrokerController,並且調用其初始化方法

 

大家去看Broker的源碼的話會發現,他的初始化流程很冗長,會根據配置創建很多線程池主要用來發送消息拉取消息查詢消息客戶端管理消費者管理,也有很多定時任務,同時也註冊了很多請求處理器,用來發送拉取消息查詢消息的。

Consumer

不說了直接懟圖吧!要死了,下次我還是做掃盲,寫點爽文吧555

 

Consumer是消息接受,那他怎麼接收消息的呢?

 

消費端會通過RebalanceService線程,10秒鐘做一次基於Topic下的所有隊列負載。

面試常見問題分析

他的優缺點是啥

RocketMQ優點:

  • 單機吞吐量:十萬級

  • 可用性:非常高,分佈式架構

  • 消息可靠性:經過參數優化配置,消息可以做到0丟失

  • 功能支持:MQ功能較爲完善,還是分佈式的,擴展性好

  • 支持10億級別的消息堆積,不會因爲堆積導致性能下降

  • 源碼是java,我們可以自己閱讀源碼,定製自己公司的MQ,可以掌控

  • 天生爲金融互聯網領域而生,對於可靠性要求很高的場景,尤其是電商裏面的訂單扣款,以及業務削峯,在大量交易湧入時,後端可能無法及時處理的情況

  • RoketMQ在穩定性上可能更值得信賴,這些業務場景在阿里雙11已經經歷了多次考驗,如果你的業務有上述併發場景,建議可以選擇RocketMQ

RocketMQ缺點:

  • 支持的客戶端語言不多,目前是java及c++,其中c++不成熟

  • 社區活躍度不是特別活躍那種

  • 沒有在 mq 核心中去實現JMS等接口,有些系統要遷移需要修改大量代碼

消息去重

去重原則:使用業務端邏輯保持冪等性

冪等性:就是用戶對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因爲多次點擊而產生了副作用,數據庫的結果都是唯一的,不可變的。

只要保持冪等性,不管來多少條重複消息,最後處理的結果都一樣,需要業務端來實現。

去重策略:保證每條消息都有唯一編號(比如唯一流水號),且保證消息處理成功與去重表的日誌同時出現。

建立一個消息表,拿到這個消息做數據庫的insert操作。給這個消息做一個唯一主鍵(primary key)或者唯一約束,那麼就算出現重複消費的情況,就會導致主鍵衝突,那麼就不再處理這條消息。

消息重複

消息領域有一個對消息投遞的QoS定義,分爲:

  • 最多一次(At most once)
  • 至少一次(At least once)
  • 僅一次( Exactly once)

QoS:Quality of Service,服務質量

幾乎所有的MQ產品都聲稱自己做到了At least once

既然是至少一次,那避免不了消息重複,尤其是在分佈式網絡環境下。

比如:網絡原因閃斷,ACK返回失敗等等故障,確認信息沒有傳送到消息隊列,導致消息隊列不知道自己已經消費過該消息了,再次將該消息分發給其他的消費者。

不同的消息隊列發送的確認信息形式不同,例如RabbitMQ是發送一個ACK確認消息,RocketMQ是返回一個CONSUME_SUCCESS成功標誌,Kafka實際上有個offset的概念。

RocketMQ沒有內置消息去重的解決方案,最新版本是否支持還需確認。

消息的可用性

當我們選擇好了集羣模式之後,那麼我們需要關心的就是怎麼去存儲和複製這個數據,RocketMQ對消息的刷盤提供了同步和異步的策略來滿足我們的,當我們選擇同步刷盤之後,如果刷盤超時會給返回FLUSH_DISK_TIMEOUT,如果是異步刷盤不會返回刷盤相關信息,選擇同步刷盤可以盡最大程度滿足我們的消息不會丟失。

除了存儲有選擇之後,我們的主從同步提供了同步和異步兩種模式來進行復制,當然選擇同步可以提升可用性,但是消息的發送RT時間會下降10%左右。

RocketMQ採用的是混合型的存儲結構,即爲Broker單個實例下所有的隊列共用一個日誌數據文件(即爲CommitLog)來存儲。

Kafka採用的是獨立型的存儲結構,每個隊列一個文件。

這裏帥丙認爲,RocketMQ採用混合型存儲結構的缺點在於,會存在較多的隨機讀操作,因此讀的效率偏低。同時消費消息需要依賴ConsumeQueue,構建該邏輯消費隊列需要一定開銷。

RocketMQ 刷盤實現

Broker 在消息的存取時直接操作的是內存(內存映射文件),這可以提供系統的吞吐量,但是無法避免機器掉電時數據丟失,所以需要持久化到磁盤中。

刷盤的最終實現都是使用NIO中的 MappedByteBuffer.force() 將映射區的數據寫入到磁盤,如果是同步刷盤的話,在Broker把消息寫到CommitLog映射區後,就會等待寫入完成。

異步而言,只是喚醒對應的線程,不保證執行的時機,流程如圖所示。

 

順序消息:

我簡單的說一下我們使用的RocketMQ裏面的一個簡單實現吧。

Tip:爲啥用RocketMQ舉例呢,這玩意是阿里開源的,我問了下身邊的朋友很多公司都有使用,所以讀者大概率是這個的話我就用這個舉例吧,具體的細節我後面會在RocketMQKafka各自章節說到。

生產者消費者一般需要保證順序消息的話,可能就是一個業務場景下的,比如訂單的創建、支付、發貨、收貨。

那這些東西是不是一個訂單號呢?一個訂單的肯定是一個訂單號的說,那簡單了呀。

一個topic下有多個隊列,爲了保證發送有序,RocketMQ提供了MessageQueueSelector隊列選擇機制,他有三種實現:

 

我們可使用Hash取模法,讓同一個訂單發送到同一個隊列中,再使用同步發送,只有同個訂單的創建消息發送成功,再發送支付消息。這樣,我們保證了發送有序。

RocketMQ的topic內的隊列機制,可以保證存儲滿足FIFO(First Input First Output 簡單說就是指先進先出),剩下的只需要消費者順序消費即可。

RocketMQ僅保證順序發送,順序消費由消費者業務保證!!!

這裏很好理解,一個訂單你發送的時候放到一個隊列裏面去,你同一個的訂單號Hash一下是不是還是一樣的結果,那肯定是一個消費者消費,那順序是不是就保證了?

真正的順序消費不同的中間件都有自己的不同實現我這裏就舉個例子,大家思路理解下。

分佈式事務:

Half Message(半消息)

是指暫不能被Consumer消費的消息。Producer 已經把消息成功發送到了 Broker 端,但此消息被標記爲暫不能投遞狀態,處於該種狀態下的消息稱爲半消息。需要 Producer

對消息的二次確認後,Consumer才能去消費它。

消息回查

由於網絡閃段,生產者應用重啓等原因。導致 Producer 端一直沒有對 Half Message(半消息) 進行 二次確認。這是Brock服務器會定時掃描長期處於半消息的消息,會

主動詢問 Producer端 該消息的最終狀態(Commit或者Rollback),該消息即爲 消息回查

 

  1. A服務先發送個Half Message給Brock端,消息中攜帶 B服務 即將要+100元的信息。
  2. 當A服務知道Half Message發送成功後,那麼開始第3步執行本地事務。
  3. 執行本地事務(會有三種情況1、執行成功。2、執行失敗。3、網絡等原因導致沒有響應)
  4. 如果本地事務成功,那麼Product像Brock服務器發送Commit,這樣B服務就可以消費該message。
  5. 如果本地事務失敗,那麼Product像Brock服務器發送Rollback,那麼就會直接刪除上面這條半消息。
  6. 如果因爲網絡等原因遲遲沒有返回失敗還是成功,那麼會執行RocketMQ的回調接口,來進行事務的回查。

消息過濾

  • Broker端消息過濾  
    Broker中,按照Consumer的要求做過濾,優點是減少了對於Consumer無用消息的網絡傳輸。缺點是增加了Broker的負擔,實現相對複雜。
  • Consumer端消息過濾
    這種過濾方式可由應用完全自定義實現,但是缺點是很多無用的消息要傳輸到Consumer端。

Broker的Buffer問題

Broker的Buffer通常指的是Broker中一個隊列的內存Buffer大小,這類Buffer通常大小有限。

另外,RocketMQ沒有內存Buffer概念,RocketMQ的隊列都是持久化磁盤,數據定期清除。

RocketMQ同其他MQ有非常顯著的區別,RocketMQ的內存Buffer抽象成一個無限長度的隊列,不管有多少數據進來都能裝得下,這個無限是有前提的,Broker會定期刪除過期的數據。

例如Broker只保存3天的消息,那麼這個Buffer雖然長度無限,但是3天前的數據會被從隊尾刪除。

回溯消費

回溯消費是指Consumer已經消費成功的消息,由於業務上的需求需要重新消費,要支持此功能,Broker在向Consumer投遞成功消息後,消息仍然需要保留。並且重新消費一般是按照時間維度。

例如由於Consumer系統故障,恢復後需要重新消費1小時前的數據,那麼Broker要提供一種機制,可以按照時間維度來回退消費進度。

RocketMQ支持按照時間回溯消費,時間維度精確到毫秒,可以向前回溯,也可以向後回溯。

消息堆積

消息中間件的主要功能是異步解耦,還有個重要功能是擋住前端的數據洪峯,保證後端系統的穩定性,這就要求消息中間件具有一定的消息堆積能力,消息堆積分以下兩種情況:

  • 消息堆積在內存Buffer,一旦超過內存Buffer,可以根據一定的丟棄策略來丟棄消息,如CORBA Notification規範中描述。適合能容忍丟棄消息的業務,這種情況消息的堆積能力主要在於內存Buffer大小,而且消息堆積後,性能下降不會太大,因爲內存中數據多少對於對外提供的訪問能力影響有限。
  • 消息堆積到持久化存儲系統中,例如DB,KV存儲,文件記錄形式。 當消息不能在內存Cache命中時,要不可避免的訪問磁盤,會產生大量讀IO,讀IO的吞吐量直接決定了消息堆積後的訪問能力。
  • 評估消息堆積能力主要有以下四點:
  • 消息能堆積多少條,多少字節?即消息的堆積容量。
  • 消息堆積後,發消息的吞吐量大小,是否會受堆積影響?
  • 消息堆積後,正常消費的Consumer是否會受影響?
  • 消息堆積後,訪問堆積在磁盤的消息時,吞吐量有多大?

定時消息

定時消息是指消息發到Broker後,不能立刻被Consumer消費,要到特定的時間點或者等待特定的時間後才能被消費。

如果要支持任意的時間精度,在Broker層面,必須要做消息排序,如果再涉及到持久化,那麼消息排序要不可避免的產生巨大性能開銷。

RocketMQ支持定時消息,但是不支持任意時間精度,支持特定的level,例如定時5s,10s,1m等。

總結

寫這種單純介紹中間件的枯燥乏味,大家看起來估計也累,目前已經破一萬個字了,以後我這種類型的少寫,大家老是讓我寫點深度的,我說真的很多東西我源碼一貼,看都沒人看。

Kafka我就不發博客了,大家可以去GItHub上第一時間閱讀,後面會出怎麼搭建項目在服務器的教程,還有一些大牛個人經歷和個人書單的東西,今年應該先這麼寫,主要是真心太忙了,望理解。


鏈接:https://juejin.im/post/5de3c8026fb9a07194761641
 

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