全稱(message queue)消息隊列,一個用於接收消息、存儲消息並轉發消息的中間件linux
用於解決的場景,總之是能接收消息並轉發消息緩存
總之MQ是能夠存放消息並轉發消息的中間件,場景取決於拿這個能力去解決什麼問題網絡
MQ向別人承諾的場景是接收消息,存儲,並能夠轉發消息異步
接收消息,那麼接收誰的消息,爲了說明這個問題,那麼mq須要引入一個概念,叫作生產者,也就是發送消息的服務,不然沒有辦法來區分是誰發的消息,生產者經過網絡發送消息就能夠,中間的細節咱們先不探討。
那麼還有一個問題就是消息發送給誰?性能
消費消息,那麼同理的一個問題,誰消費消息,爲了說明那麼mq須要引入一個概念,叫作消費者,也就是消費消息的服務,不然沒有辦法來區分是誰在接收消息,消費者經過網絡接收消息就能夠了,中間的細節咱們先不探討。google
那麼問題來了,消費者怎麼說明消費誰的消息,上文已經說了,經過指明mq的topic,來決定我要哪一類消息。spa
至此咱們總結一下最後的模型3d
也就是最後生產者和消費者經過MQ的topic概念來實現解耦。code
說到存儲,其實效率纔是最主要的,容量不是咱們關心的,可是說到存儲,不僅是mq,全部須要高效率的存儲其實最後利用的核心都是同樣的。中間件
第一 如今主流的硬盤是機械硬盤
第二 機械硬盤的機械結構一次讀寫時間 = 尋道時間 + 旋轉延遲 + 讀取數據時間
那麼尋道時間比較長,若是是順序寫,只須要一次尋道時間,關於機械硬盤整個過程,讀者可自行google。
由於每次刷盤都會進行系統調用,第二仍是跟硬盤的自己屬性有關,不管是機械硬盤仍是ssd按照必定塊刷盤會比小數據刷盤效率更好
爲何先說kafka的存儲,由於kafka是第一個高性能的消息中間件,其中rocketmq也是借鑑於它,因此咱們先說。
先給出最終模型變化圖。
那麼模型出來了,咱們說說存儲的問題。
對於kafka,一個partition對應一個文件,每次消息來都是順序寫這個文件。而且是定時刷盤,而不是每次寫都刷盤,因此kafka的寫很是高效。
上文咱們說了rocketmq借鑑於kafka,因此存儲借鑑了kafka,可是rocketmq不是僅僅把partition改爲了ConsumeQueue,在這裏作了變化,原先kafka,裏面partition存儲的是整個消息,可是如今ConsumeQueue裏面是存儲消息的存儲地址,可是不存儲消息了。
如今每一個ConsumeQueue存儲的是每一個消息在commitlog這個文件的地址,可是消息存在於commitlog中。
也就是全部的消息體都寫在了一個文件裏面,每一個ConsumeQueue只是存儲這個消息在commitlog中地址。
消息體存儲的變化
那麼咱們先來看看kafka,假設partition有1000個,一個partition是順序寫一個文件,整體上就是1000個文件的順序寫,是否是就變成了隨機寫,因此當partition增長到必定數目後,kafka性能就會降低。而rocketmq是把消息都寫到一個CommitLog文件中,因此至關於一個文件的順序寫。
爲何索引文件(ConsumeQueue)的增長對性能影響沒有那麼partition大?
(kafka也有索引文件,在這裏只是想說明索引文件的增長跟partition增長的區別)
雖然rocketmq是把消息都寫到一個CommitLog文件中,可是按照上面的實例會有1000個ConsumeQueue,也就是一千個文件,那麼爲何就沒有把順序寫變成隨機寫,帶來性能的降低呢?首先就要介紹linux的pagecache
咱們日常調用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,也就是順序寫。
因此咱們總結下這個點:
一、consumerQueue消息格式大小固定(20字節),寫入pagecache以後被觸發刷盤頻率相對較低。就是由於每次寫入的消息小,形成他佔用的pagecache少,主要佔用方一旦被清理,那麼他就能夠不用清理了。
二、kafka中多partition會存在隨機寫的可能性,partition之間刷盤的衝撞率會高,可是rocketmq中commitLog都是順序寫。
歡迎關注博主公衆號,後面會持續更新mq系列知識點,一塊兒討論。