RabbitMq存儲機制

1.不管是持久化的消息還是非持久化的消息都可以被寫入到磁盤。

2.持久化的消息在到達隊列時就被寫入到磁盤,並且如果可以,持久化的消息也會在內存中保存一份備份,這樣可以提高一定的性能,當內存吃緊的時候會從內存中清除。

3.非持久化的消息一般只保存在內存中,在內存吃緊的時候會被換入到磁盤中,以節省內存空間。

4.這兩種類型的消息的落盤處理都在RabbitMq的“持久層”中完成。

 

持久層

1.包含兩個部分:隊列索引(rabbit_queue_index)和消息存儲(rabbit_msg_store)。

2.隊列索引負責維護隊列中落盤消息的信息,包括消息的存儲地點、是否已被交付給消費者、是否已被消費者ack等。每個隊列都有一個與之對應的一個隊列索引。

3.消息存儲已鍵值對的形式存儲消息,它被所有隊列共享,在每個節點中有且只有一個。

4.從技術上來說,消息存儲還可以分爲msg_store_persistent和msg_store_transient,msg_store_persistent負責持久化消息的持久化,重啓後消息不會丟失;msg_store_transient負責非持久化消息的持久化,重啓後消息丟失。

 

消息

1.包含消息體、屬性和headers.

2.可以直接存儲在rabbit_queue_index中,也可以被保存在rabbit_msg_store中.

3.默認在$RABBITMQ_HOST/var/lib/mnesia/rabbit@$HOSTNAME/路徑下包含queues、msg_store_persistent、msg_store_transient這3個文件夾.

 

(非默認安裝地址)

4.最佳的配備是較小的消息存儲在rabbit_queue_index中,較大的消息存儲在rabbit_msg_store中.

5.這個消息大小的界定可以通過queue_index_embed_msgs_below來配置,默認爲4096B.(這裏大小是指消息、屬性和headers整體的大小,當一個消息小於設定的大小閾值時就可以存在rabbit_queue_index中,這樣可以得到性能上的優化)

6.rabbit_queue_index中以順序(文件名從0開始累加)的段文件來進行存儲,後綴喂“.idx”,每個文件中包含固定的SEGMENT_ENTRY_COUNT(默認值爲16384)條記錄。每個rabbit_queue_index從磁盤中讀取消息的時候至少要在內存中維護一個段文件,所以設置queue_index_embed_msgs_below值得時候要格外謹慎,一點點增大也可能會引起內存爆炸式的增長.

 

7.rabbit_msg_store處理的所有消息都會以追加的方式寫入到文件中,當一個文件的大小超過指定的限制(file_size_limit)後,關閉這個文件再創建一個新的文件以供新的消息寫入。後綴名“.rdq”,在進行消息的存儲時,RabbitMq會在ETS(Erlang Term Storage)表中記錄消息在文件中的位置映射(Index)和文件的相關信息(FileSummary)。

8.在讀取消息的時候,先根據消息的ID(msg_id)找到對應存儲的文件,如果文件存在並且未被鎖住,則直接打開文件,從指定位置讀取消息的內容。如果文件不存在或者被鎖住了,則發送請求由rabbit_msg_store進行處理.

9.消息的刪除只是從ETS表刪除指定消息的相關信息,同時更新消息對應的存儲文件的相關信息。執行消息刪除操作時,並不立即對在文件中的消息進行刪除,也就是說消息依然在文件中,僅僅是標記爲垃圾數據而已。當一個文件中都是垃圾數據時可以將這個文件刪除。當檢測到前後兩個文件中的有效數據可以合併在一個文件中,並且所有的垃圾的大小和所有文件(至少有3個文件存在的情況下)的數據大小的比值超過設置的閾值GARBAGE_FRACTION(默認值爲0.5)時纔會觸發垃圾回收將兩個文件合併.

10.執行合併的兩個文件一定是邏輯上相鄰的兩個文件。執行合併時首先鎖定這兩個文件,並先對前面文件中的有效數據進行整理,再將後面文件的有效數據寫入到前面的文件,同時更新消息在ETS表中的記錄,最後刪除後面的文件.

 

隊列

1.通常隊列由rabbit_amqqueue_process和backing_queue這兩部分組成,rabbit_amqqueue_process負責協議相關的消息處理(接受生產者發佈的消息、向消費者交付消息、處理消息的確認等)。backing_queue是消息存儲的具體形式和引擎,並向rabbit_amqqueue_process提供相關的接口以供調用。

2.如果消息投遞的目的隊列是空的,並且有消費者訂閱了這個隊列,那麼該消息會知時節發送給消費者,不會經過隊列這一步

3.而當消息無法直接投遞給消費者時,需要暫時將消息存入隊列,以便重新投遞。

4.消息存入隊列後,不是固定不變,它會隨着同的負載在隊列中不斷地流動,消息狀態會不斷髮送變化。RabbitMq中的隊列消息可能會處於一下4中狀態:

A.alpha:消息內容和消息索引都存儲在內存中

B.beta:消息內容保存在磁盤中,消息索引保存在內存中

C.gamma:消息內容保存在磁盤中,消息索引在磁盤和內存中都有

D.delta:消息內容和索引都在磁盤中

5.對於持久化的消息,消息內容和消息索引都必須先保存在磁盤上,纔會處於上述狀態中的一種。而gamma狀態的消息是隻有持久化的消息纔會有的狀態.

6.RabbitMq在運行時會根據統計的消息傳送速度定期計算一個當前內存中能夠保存的最大消息數量(target_ram_count),如果alpha狀態的消息數量大於此值時,就會引起消息的狀態轉換,多餘的消息可能會轉換到beta狀態、gamma狀態和delta狀態.

7.區分這4中狀態的主要作用是滿足不同的內存和CPU需求。alpha狀態最耗內存,但很少消耗CPU。delta狀態基本不消耗內存,但是需要消耗更多的CPU和磁盤I/O操作(delta狀態需要執行兩次I/O操作才能讀取到消息:一是讀消息索引及從rabbit_queue_index中,二是讀消息內容即從rabbit_msg_store中)。beta和gamma狀態都只需要一次I/O操作就可以讀取到消息(從rabbit_msg_store中).

 

 

 

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