天天看點

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

戳藍字「TopCoder」關注我們哦!

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】
編者注:作者是Java開發工程師@青雲。

MQ初窺門徑

全稱(message queue)消息隊列,一個用于接收消息、存儲消息并轉發消息的中間件

應用場景

用于解決的場景,總之是能接收消息并轉發消息

  1. 用于異步處理,比如A服務做了什麼事情,異步發送一個消息給其他B服務。
  2. 用于削峰,有些服務(秒殺),請求量很高,服務處理不過來,那麼請求先放到消息隊列裡面,後面按照能力處理,相當于蓄水池。
  3. 應用解耦、消息通訊等等
總之MQ是可以存放消息并轉發消息的中間件,場景取決于拿這個能力去解決什麼問題

MQ概念模型

MQ向别人承諾的場景是接收消息,存儲,并可以轉發消息

接收消息

接收消息,那麼接收誰的消息,為了說明這個問題,那麼mq需要引入一個概念,叫做生産者,也就是發送消息的服務,否則沒有辦法來區分是誰發的消息,生産者通過網絡發送消息就可以,中間的細節我們先不探讨。

那麼還有一個問題就是消息發送給誰?

  1. 我在發送消息的時候,指明我要發送給誰,就像發送短信一樣,你需要指明你要發送給誰?

    這種方案在使用中是有問題的,因為在現在業務很多場景中, 發送方其實根本不知道對方是誰,他隻是将自己的狀态發送出來,那麼誰需要這個消息,誰就接收,第二個如果指明了接收方,那麼以後增加一個接收方就要改一下配置或者代碼,将發送消息的人跟接收消息的人綁定在一起了

    那麼有沒有方案,解耦的最好辦法就是中間人,也叫中間層,我隻發送給第三方,誰要消息,問第三方要,那麼相當于我把發送的目标改為發送給第三方,這裡的第三方就是mq,為了說明說明發送的地方,mq引入了topic的概念,發送方把消息發送到mq指定的一個通道中,以後誰想要這個消息,就跟mq說我想要這個通道的消息,也就是發送方發送的消息。

消費消息

消費消息,那麼同理的一個問題,誰消費消息,為了說明那麼mq需要引入一個概念,叫做消費者,也就是消費消息的服務,否則沒有辦法來區分是誰在接收消息,消費者通過網絡接收消息就可以了,中間的細節我們先不探讨。

那麼問題來了,消費者怎麼說明消費誰的消息,上文已經說了,通過指明mq的topic,來決定我要哪一類消息。至此我們總結一下最後的模型,也就是最後生産者和消費者通過MQ的topic概念來實作解耦。

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

存儲

說到存儲,其實效率才是最主要的,容量不是我們關心的,但是說到存儲,不隻是mq,所有需要高效率的存儲其實最後利用的核心都是一樣的。

1.随機寫轉換成順序寫

2.集中刷盤

為什麼随機寫要轉換為順序寫?

第一 現在主流的硬碟是機械硬碟

第二 機械硬碟的機械結構一次讀寫時間 = 尋道時間 + 旋轉延遲 + 讀取資料時間

那麼尋道時間比較長,如果是順序寫,隻需要一次尋道時間,關于機械硬碟整個過程,讀者可自行google。

為什麼集中刷盤?

因為每次刷盤都會進行系統調用,第二還是跟硬碟的本身屬性有關,無論是機械硬碟還是ssd按照一定塊刷盤會比小資料刷盤效率更好

kafka

為什麼先說kafka的存儲,因為kafka是第一個高性能的消息中間件,其中rocketmq也是借鑒于它,是以我們先說。

先給出最終模型變化圖

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】
  1. 為什麼引入消費組概念?

    上一次模型圖我們還沒有消費組,那麼引入消費組,是因為現在一個服務都有很多執行個體在運作,消費組是對這群一群機器的一個劃分,他還是一個概念而已。

  2. mq内部也發生了變化,一個topic後面又對應了很多partition,partition也是一個概念,他隻不過是把一個topic分成了很多份,每一份叫一個partition,你高興也可以叫他xxx,那麼我們來說說為什麼要分成很多份,一份不行嗎?

    因為現在一個服務有很多執行個體在運作,如果topic隻有一份的話,那麼所有的執行個體都會來消費消息,并且都是搶占我們一個topic,這不可避免引入了多執行個體競争,以及他們之間怎麼協調,一堆問題需要關注解決,現在我把topic分成了很多份,每一份隻給一個執行個體,那麼就不會引入各執行個體之間的競争問題了,簡化了mq的問題。

  3. 生産組的引入也是一樣的,隻不過是一組機器的一個概念,一個邏輯的劃分,生産者發送消息原先是發往topic,那麼現在topic分成了很多份,生産者發送消息,需要說明發往哪個partition或者随意配置設定都可以,隻不過最終發送的消息,會到一個topic下的一份裡面。無論使用哪種映射方式都可以。

那麼模型出來了,我們說說存儲的問題。

對于kafka,一個partition對應一個檔案,每次消息來都是順序寫這個檔案。并且是定時刷盤,而不是每次寫都刷盤,是以kafka的寫非常高效。

rocketmq

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

上文我們說了rocketmq借鑒于kafka,是以存儲借鑒了kafka,但是rocketmq不是僅僅把partition改成了ConsumeQueue,在這裡做了變化,原先kafka,裡面partition存儲的是整個消息,但是現在ConsumeQueue裡面是存儲消息的存儲位址,但是不存儲消息了。

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

現在每個ConsumeQueue存儲的是每個消息在commitlog這個檔案的位址,但是消息存在于commitlog中。

也就是所有的消息體都寫在了一個檔案裡面,每個ConsumeQueue隻是存儲這個消息在commitlog中位址。

存儲對比

  1. 消息體存儲的變化

    那麼我們先來看看kafka,假設partition有1000個,一個partition是順序寫一個檔案,總體上就是1000個檔案的順序寫,是不是就變成了随機寫,是以當partition增加到一定數目後,kafka性能就會下降。而rocketmq是把消息都寫到一個CommitLog檔案中,是以相當于一個檔案的順序寫。

  2. 為什麼索引檔案(ConsumeQueue)的增加對性能影響沒有那麼partition大?

    (kafka也有索引檔案,在這裡隻是想說明索引檔案的增加跟partition增加的差別)

    雖然rocketmq是把消息都寫到一個CommitLog檔案中,但是按照上面的執行個體會有1000個ConsumeQueue,也就是一千個檔案,那麼為什麼就沒有把順序寫變成随機寫,帶來性能的下降呢?首先就要介紹linux的pagecache

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

我們平常調用write或者fwrite的時候,資料還沒有寫到磁盤上,隻是寫到一個核心的緩存(pagecache),隻有當我們主動調用flush的時候才會寫到硬碟中。或者需要回寫的pagecache占總記憶體一定比例的時候或者一個應該回寫的page超過一定時間還沒有寫磁盤的時候,核心會将這些資料通過背景程序寫到磁盤中(總結就是達到一定比例,或者多長時間還沒有回寫,會被核心自動回寫)。

然後我們現在來看看為什麼大量索引檔案的順序寫沒有像partition一樣導緻性能明顯下降。ConsumeQueue隻存儲了(CommitLog Offet + Size + Message Tag Hashcode),一共20個位元組,那麼當commitlog定時任務刷盤之後,應該回寫的pagecache的比例就會下降很多,那麼ConsumeQueue的部分可以不用刷盤,就相當于ConsumeQueue的内容會等待比較長的時間聚合批量寫入,而kafka每個partition都是存儲的消息體,因為消息體都相對較大,基本在kb之上。

當一個partition刷盤的時候,應該回寫的pagecache的比例降低的并不多,不能阻止其他partition的刷盤,是以會大量存在多個partition同時刷盤的場景,變成随機寫。但是rocketmq消息都會寫入一個commitLog,也就是順序寫。

是以我們總結下這個點:

1、consumerQueue消息格式大小固定(20位元組),寫入pagecache之後被觸發刷盤頻率相對較低。就是因為每次寫入的消息小,造成他占用的pagecache少,主要占用方一旦被清理,那麼他就可以不用清理了。

2、kafka中多partition會存在随機寫的可能性,partition之間刷盤的沖撞率會高,但是rocketmq中commitLog都是順序寫。

往期精選
  • sentinel 核心概念
  • sentinel 滑動視窗統計機制
  • sentinel 叢集流控原理
  • sentinel dubbo适配機制
  • 分布式鎖設計與實作
  • 常見限流方案設計與實作
  • 如何用好redis pipeline

覺得文章不錯,對你有所啟發和幫助,希望能轉發給更多的小夥伴。如果有問題,請關注下面公衆号,發送問題給我,多謝。

歡迎小夥伴

關注【TopCoder】

閱讀更多精彩好文。

flink1.11從kafka寫到kafka table_MQ初窺門徑【面試必看的Kafka和RocketMQ存儲差別】

繼續閱讀