深入理解RocketMQ是如何做到高性能的?
1、RocketMQ的核心Broker
對rocketmq稍有了解的同學,都知道它主要由4部分組成,Producer、Consumer、Broker、NameServer。
Broker作為Rocket MQ的核心,提供了強大的數據存儲能力,可以把億萬級的消息存儲在服務器磁盤上。它決定了生產者寫入的吞吐量,決定了消息不能丟失,決定了消費者消費消息的吞吐量。
2、消息寫入磁盤文件:CommitLog
當生產者的消息發送到一個Broker上的時候,它接收到了一條消息,會對這個消息做什么處理?
首先第一步,他會把這個消息直接寫入磁盤上的一個日志文件,沒錯就是磁盤文件,它叫做CommitLog,直接順序寫入這個文件,如下圖。
圖1?消息順序寫入CommitLog文件
這個CommitLog文件默認大小是1G,如果消息很多的話,可能會創建很多個CommitLog文件。
CommitLog文件的文件名長度為20位,左邊補零,剩余為起始偏移量,比如00000000000000000000代表了第一個文件,起始偏移量為0,文件大小為1G=1073741824;當第一個文件寫滿了,第二個文件為00000000001073741824,起始偏移量為1073741824,以此類推。
圖2?CommitLog文件
Broker收到消息后,直接追加到這個文件的末尾。
3、消息的偏移量寫入磁盤文件:ConsumeQueue
我們知道每個Topic可能對應了多個Queue,那么這些Queue在Broker中是如何體現的呢?
其實在Broker中,每個Topic下的每個Queue都會對應一些列的ConsumeQueue文件。
圖3 Broker本地存儲文件
就是在Broker磁盤上,會有下面這種格式的一些列文件:
~/store/consumequeue/{topic}/{queueId}/{fileName}
{topic}指代的就是某個Topic,{queueId}指代的就是某個MessageQueue。
然后存儲在這臺Broker機器上的Topic下的一個MessageQueue,他有很多的ConsumeQueue文件,這個ConsumeQueue文件里存儲的是一條消息對應在CommitLog文件中的offset偏移量。
這點比較重要,ConsumeQueue不存儲真實的消息數據,只存消息數據在CommitLog文件中的偏移量。
假設有一個Topic,他有4個Queue,然后分布在兩臺Broker機器上,每臺Broker機器會存儲兩個Queue。
此時生產者選擇對其中一個Queue寫入了一條消息,此時消息會發送到Broker上。
然后然后Broker會把這個消息寫入CommitLog文件中,同時會把消息的偏移量寫入兩個ConsumeQueue中,ConsumeQueue0和ConsumeQueue1。它們分別對應著Topic里的Queue0和Queue1。
圖4?消息偏移量寫入ConsumeQueue文件中
也就是說,Topic下的Queue0和Queue1就放在這個Broker機器上,而它們每個在磁盤上對應了一個ConsumeQueue文件,所以就是Queue0對應著Broker磁盤上的ConsumeQueue0,Queue1對應著磁盤上的ConsumeQueue1。
假設Queue的名字叫做:TopicOrderInfo,Queue0的id是0,Queue1的id是1,那么此時在Broker磁盤上應該有如下兩個路徑的文件:
~/store/consumequeue/TopicOrderInfo/0/ConsumeQueue0文件
~/store/consumequeue/TopicOrderInfo/1/ConsumeQueue1文件
圖5?ConsumeQueue本地磁盤文件
然后,當你的Broker收到一條消息寫入了CommitLog之后,其實他同時會將這條消息在CommitLog中的物理位置,也就是一個文件偏移量(offset),寫入到這條消息所屬的Queue對應的ConsumeQueue文件中去。
ConsumeQueue文件存在的目的就是可以快速定位到消息真實的物理位置,在ConsumeQueue中存儲的每條數據不只是消息在CommitLog中的offset偏移量,還包含了消息的長度,以及tag hashcode,一條數據是20個字節,每個ConsumeQueue文件保存30萬條數據,所以計算下來每個文件是5.72MB。
需要注意的是每個Topic的每個Queue都對應了Broker機器上的多個ConsumeQueue文件,保存了這個MessageQueue的所有消息在CommitLog文件中的物理位置,也就是offset偏移量。
4、RocketMQ是如何提升CommitLog寫入性能的?
CommitLog作為存儲消息的核心所在,關乎著整個消息隊列的吞吐量。那么Broker是如何提升整個過程的性能的呢?
Broker是基于OS操作系統的PageCache和順序寫兩個機制,來提升寫入CommitLog文件的性能的。
首先Broker是以順序的方式將消息寫入CommitLog磁盤文件的,也就是每次寫入就是在文件末尾追加一條數據就可以了,對文件進行順序寫的性能要比對文件隨機寫的性能提升很多。
另外,消息寫入CommitLog文件的時候,并不是直接寫入磁盤文件的,而是先進入OS的PageCache內存緩存中,然后再由OS的后臺線程選一個時間,異步化的將OS PageCache內存緩沖中的數據刷入底層的磁盤文件。
圖6?異步刷盤CommitLog文件
在采用磁盤文件順序寫+OS PageCache寫入+OS異步刷盤的策略,基本上可以讓消息寫入CommitLog的性能接近直接寫入內存,所以正是如此,才可以讓Broker高吞吐的處理每秒大量的消息寫入。
5、異步刷盤的利弊
很多時候魚和熊掌不可兼得,我們充分提升性能的同時,就會犧牲一些高可用性。
如果生產者認為消息寫入成功了,但是實際上那條消息此時是在Broker機器上的os cache中的,如果此時Broker直接宕機,那么是不是os cache中的這條數據就會丟失了?
所以異步刷盤的的策略下,可以讓消息寫入吞吐量非常高,但是可能會有數據丟失的風險。
所以rocketmq提供了同步刷盤,讓使用者可選擇。如果你使用同步刷盤模式的話,那么生產者發送一條消息出去,broker收到了消息,必須直接強制把這個消息刷入底層的物理磁盤文件中,然后才會返回ack給producer,此時你才知道消息寫入成功了。
但是如果你強制每次消息寫入都要直接進入磁盤中,必然導致每條消息寫入性能急劇下降,導致消息寫入吞吐量急劇下降,但是可以保證數據不會丟失。具體如何選擇,還需要看你的業務場景。
6、總結
這篇文章主要講broker最為核心的數據存儲機制,希望伙伴們不只是記住,也要理解思考,為什么這樣設計,自己的項目中是否有可以借鑒學習的地方。
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的深入理解RocketMQ是如何做到高性能的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑键盘练习_三款神器!超越键盘飞毛腿!
- 下一篇: 去了家新公司,技术总监不让用 Intel