RocketMQ存儲設計精髓
?
點擊關注公眾號,Java干貨及時送達
另外在進行消息消費的時候,RocketMQ如何能借助自身的存儲設計快速檢索到對應的消息也是非常重要的,因此本文主要對RocketMQ存儲設計進行了設計分析。
存儲結構
RocketMQ對應的存儲文件主要包括三類,分別是Commitlog文件、ConsumeQueue文件以及Index文件,每一個文件都有其特殊的使命。
Commitlog文件
當生產(chǎn)者將消息發(fā)送到RocketMQ的Broker之后,需要將消息進行持久化存儲,防止消息數(shù)據(jù)丟失。RocketMQ將消息數(shù)據(jù)寫入存儲文件CommitLog中,按照消息的發(fā)送順序?qū)懭胛募斨校總€文件的大小約為1G,當達到文件大小限制后,就會創(chuàng)建新的CommitLog文件。RocketMQ作為消息中間件來說,最主要的數(shù)據(jù)流程就是基于主題的發(fā)布-訂閱模式進行消息的發(fā)布以及消費,那么當消費者根據(jù)自己訂閱的Topic進行消息消費的時候,Broker怎么在那么多的CommitLog文件中找到對應Topic的消息數(shù)據(jù)呢?

大家可以想一想,CommitLog文件中的消息數(shù)據(jù)是一條一條順序?qū)懙?,最笨的方法就是遍歷文件,作為一款高性能的消息中間件,顯然這不是一個好的解決方案。
就像從數(shù)據(jù)庫查詢數(shù)據(jù)的時候,遍歷的效率肯定是很低的。那么我們可不可以借助數(shù)據(jù)庫提升數(shù)據(jù)查詢的方式,使用索引來加快消息數(shù)據(jù)的查詢呢?答案是肯定的。就像Mysql中的索引本身需要文件保存一樣,在RocketMQ中也有單獨保存索引的文件,就是ConsumerQueue文件。
ConsumerQueue文件
在RocketMQ中,每個Topic對應多個MessageQueue,每個MessageQueue對應一組ConsumerQueue文件索引文件。ConsumerQueue文件中存儲了消息相對于CommitLog文件的offset偏移量,CommitLog文件本身實際上也是通過偏移量來進行命名如第一個文件是0000000000000,那么第二文件就是消息總量之和00000001232321,往后新的文件再進行累計。為什么這么做呢?主要就是在進行消息查找的時候根據(jù)消息的偏移量通過二分查找快速定位具體的CommitLog文件,提升消息查找效率。需要說明的是,Broker在進行消息寫入CommitLog文件中就會異步將其對應的偏移量寫入ConsumerQueue文件中。

在ConsumerQueue文件中實際存儲了CommitLog文件的offset偏移量、消息長度以及tag的hashcode,組成20字節(jié)的block塊。其在Broker上面的存儲路徑大致是:.../store/consumequeue/{topic}/{queueid}/{file}。
其中topic就是生產(chǎn)中訂閱的主題,因此消費者在消費消息的時候,Broker會根據(jù)其對應的Topic找到對應的 ?ConsumerQueue文件,進而找到其索引位置,再到CommitLog文件中直接定位具體的消息。
Index文件
另外RocketMQ的特性功能就是可以實現(xiàn)按照消息的屬性進行消息搜索,即建立了索引 Key 的 hashcode 與物理偏移量的映射關系,根據(jù) key 先快速定義到 commitlog 文件。
存儲性能設計精髓
上文中為大家闡述了RocketMQ關于存儲結構的設計,優(yōu)秀的存儲設計師實現(xiàn)高性能讀寫的前提。那么除了存儲結構的設計,RocketMQ也使用了一些性能優(yōu)化手段來實現(xiàn)其強大的消息吞吐能力。消息順序?qū)?/span>
前文中說過,消息進入RocketMQ之后,消息數(shù)據(jù)是通過順序?qū)懙姆绞铰涞紺ommitLog文件中的。那么這里面就涉及兩個問題,為什么進行順序?qū)懸约笆遣皇侵苯訉懘疟P文件。
1、為什么要順序?qū)懀?/span>
當新的數(shù)據(jù)到來時,只要在之前的文件末尾進行數(shù)據(jù)追加就可以,這樣的數(shù)據(jù)寫入效率要比隨機寫入的效率高。2、每次數(shù)據(jù)寫入的時候是直接寫磁盤文件嗎?
我們可以反過想,如果每次都是落盤寫入的話實際效率是不高的,無法滿足消息中間件這種高吞吐的性能要求,因此RocketMQ實際是借助操作系統(tǒng)的page cache來提升寫入效率的,消息并不是直接寫入磁盤,而是先寫入操作系統(tǒng)的page cache,然后再通過異步刷盤的方式,寫入CommitLog文件中,這樣借助順序?qū)懸约跋到y(tǒng)的page cache可以時間近乎內(nèi)存的數(shù)據(jù)寫入效率。同步刷盤和異步刷盤
異步刷盤
剛才所說的異步寫入,其實就是RocketMQ的異步刷盤模式,但是大家想想這個模式有沒有什么問題。為了提升數(shù)據(jù)吞吐量,消息數(shù)據(jù)過來后,并沒有直接寫盤,而是在系統(tǒng)中的page cache中。那么此時如果Broker宕機了,那么此時的消息數(shù)據(jù)是容易丟失的。所以雖然異步刷盤的寫入效率高但是也存在數(shù)據(jù)丟失的風險。同步刷盤
在同步刷盤的場景下,當Broker接受到對應的消息之后,Broker將會把這條消息刷入磁盤的CommitLog中,才會返回確認消息給生產(chǎn)者。如果在進行消息寫入的時候Broker掛了,那么生產(chǎn)者會感受到消息投遞失敗,一般都會都有消息重新發(fā)送的重試邏輯。這樣看消息似乎不會丟失了,但是由于每次都是先落盤,就會導致數(shù)據(jù)寫入性能下降。MMAP
在RocketMQ中使用了mmap技術來實現(xiàn)Conmmitlog文件的高性能讀寫,mmap就是一種內(nèi)存映射文件的方法,對于傳統(tǒng)的文件IO交互來說,需要經(jīng)過多次的數(shù)據(jù)復制過程才能將用戶進程的數(shù)據(jù)寫入硬盤或者讀入程序。而mmap可以直接將虛擬內(nèi)存中的文件與硬盤中文件地址進行映射,減少了數(shù)據(jù)拷貝的過程,從而提升了數(shù)據(jù)寫入的效率。
總結
本文主要對RocketMQ的存儲設計進行了分析,圍繞如何實現(xiàn)高性能消息寫入和查詢展開了闡述,希望在分析這些優(yōu)秀中間的具體實現(xiàn)過程中,我們可以將這些優(yōu)秀設計融入到具體的項目實踐中,當我們遇到類似的問題的時候可以借助于這些設計思想來解決實際的問題。往期推薦
2、銷量5年暴增25倍的TWS耳機你買了嗎?售價或會再跌20%
4、Windows重要功能被閹割,全球用戶怒噴數(shù)月后微軟終于悔改
5、牛逼!國產(chǎn)開源的遠程桌面火了,只有9MB 支持自建中繼器!

點分享

點收藏

點點贊

點在看
評論
圖片
表情
