您好,登錄后才能下訂單哦!
本篇文章為大家展示了RabbitMQ存儲原理和隊列結構是什么,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
首先確認一個點,持久化和非持久化的消息都會落地磁盤,區別在于持久化的消息一定會寫入磁盤(并且如果可以在內存中也會有一份),而非持久化的消息只有在內存吃緊的時候落地磁盤。兩種類型消息的落盤都是在RabbitMQ的持久層中完成的。
RabbitMQ的持久層只是一個邏輯上的概念,實際包含兩個部分:
隊列索引(rabbit_queue_index):負責維護隊列中落盤消息的信息,包括消息的存儲地點、是否己被交付給消費者、是否己被消費者ack等。 每個隊列都有與之對應的一個rabbit_queue_index
消息存儲(rabbit_msg_store):以鍵值對的形式存儲消息,它被所有vhost中的隊列共享,在每個vhost中有且只有一個。rabbit_msg_store具體還可以分為 msg_store_persistent和msg_store_transient,msg_store_persistent負責持久化消息的持久化,重啟后消息不會丟失;msg_store_transient負責 非持久化消息的持久化,重啟后消息會丟失。
消息(包括消息體、屬性和headers)可以直接存儲在rabbit_queue_index中,也可以被保存在rabbit_msg_store中。
最佳的配備方式是較小的消息存儲在rabbit_queue_index中而較大的信息則存儲在rabbit_msg_store中。消息大小的參數可以通過queue_index_embed_mgs_below來配置,默認大小4096,單位B。
rabbit_queue_index中以順序的段文件來開始存儲,后綴為".idx",每個段文件中包含固定的SEGMENT_ENTRY_COUNT條記錄,SEGMENT_ENTRY_COUNT默認值是16384。
經過rabbit_msg_store處理的所有消息都會以追加的方式寫入到文件中,當一個文件的大小超過指定的限制(filesizelimit)后,關閉這個文件再創建一個新的文件以供新的消息寫入。文件名(文件后綴是".rdq")從0開始進行累加,因此文件名最小的文件也是最老的文件。在進行消息的存儲時,RabbitMQ會在ETS(Erlang Term Storage)表中記錄消息在文件中的位置映射(Index)和文件的相關信息(FileSummary)。
在讀取消息的時候,先根據消息的ID(msg id)找到對應存儲的文件,如果文件存在并且未被鎖住,則直接打開文件,從指定位置讀取消息的內容。如果文件不存在或者被鎖住了,則發送請求由rabbit_msg_store進行處理。
消息刪除是只是刪除ETS表中該消息的相關信息,同時更新消息對應的存儲文件的相關信息。執行消息刪除操作時,并不立即對文件中的消息進行刪除,也就是說消息依然在文件中,僅僅是被標識為垃圾數據而已。一個文件中都是垃圾數據時可以將這個文件刪除。當檢測到前后兩個文件中的有效數據可以合并在一個文件中,并且所有的垃圾數據的大小和所有文件(至少有3個文件存在的情況下)的數據大小的比值超過設置的閥值GARBAGE FRACTION(默認值為0.5)時才會觸發垃圾回收將兩個文件合并。
通常隊列由rabbit_amqpqueue_process和backing_queue兩部分組成:
rabbit_amqpqueue_process:負責協議相關的消息處理(即接收生產者發布的消息、向消費者交付消息、處理消息的確認(包括生產端的confirm和消費端的ack))等
backing_queue:消息存儲的具體形式和引擎,并向rabbit_amqpqueue_process提供接口以供調用
如果消息發送的隊列是空的且隊列有消費者,該消息不會經過該隊列直接發往消費者,如果無法直接被消費,則需要將消息暫存入隊列,以便重新投遞。消息在存入隊列后,主要有以下幾種狀態:
alpha:消息內容(包括消息體、屬性和headers)和消息索引都存在內存中
beta:消息內容保存在磁盤中,消息索引都存在內存中
gamma:消息內容保存在磁盤中,消息索引在磁盤和內存中都存在
delta:消息內容和消息索引都在磁盤中
持久化的消息,消息內容和消息索引必須都保存在磁盤中,才會處于上面狀態中的一種,gamma狀態只有持久化的消息才有這種狀態。
對于沒有設置優先級和鏡像的隊列來說,backing_queue的默認實現是rabbit_variable_queue,其內部通過5個子隊列來體現消息的各個狀態:
Q1:只包含alpha狀態的消息
Q2:包含beta和gamma的消息
Delta:包含delta的消息
Q3:包含beta和gamma的消息
Q4:只包含alpha狀態的消息
消息的狀態一般變更方向是Q1->Q2->Delta->Q3->Q4,大體是從內存到磁盤然后再到內存中。消費者消費消息也會引起消息狀態的轉換。
消費者消費時先從Q4獲取消息,如果獲取成功則返回。
如果Q4為空,則從Q3中獲取消息,首先判斷Q3是否為空,如果為空返回隊列為空,即此時隊列中無消息
如果Q3不為空,取出Q3的消息,然后判斷Q3和Delta中的長度,如果都為空,那么Q2、Delta、Q3、Q4都為空,直接將Q1中的消息轉移至Q4,下次直接從Q4中讀取消息
如果Q3為空,Delta不為空,則將Delta中的消息轉移至Q3中,下次直接從Q3中讀取。
在將消息從Delta轉移至Q3的過程中,是按照索引分段讀取,首先讀取某一段,然后判斷讀取的消息個數和Delta消息的個數,如果相等,判定Delta已無消息,直接將讀取 Q2和讀取到消息一并放入Q3,如果不相等,僅將此次讀取的消息轉移到Q3。
通常在負載正常時,如果消息被消費的速度不小于接收新消息的速度,對于不需要保證可靠不丟失的消息來說,極有可能只會處于alpha狀態。對于durable屬性設置為true的消息,它一定會進入gamma狀態,并且在開啟publisher confirm機制時,只有到了gamma狀態時才會確認該消息己被接收,若消息消費速度足夠快、內存也充足,這些消息也不會繼續走到下一個狀態。
惰性隊列會將接收到的消息直接存入文件系統中,而不管是持久化的或者是非持久化的,這樣可以減少了內存的消耗,但是會增加I/0的使用,如果消息是持久化的,那么這樣的I/0操作不可避免,惰性隊列和持久化的消息可謂是"最佳拍檔"。
隊列具備兩種模式:default和lazy。在隊列聲明的時候可以通過x-queue-mode參數來設置隊列的模式,取值為default和lazy。對應的 Policy設置方式為:
rabbitmqctl set_policy lazy "^myQueue$" '{"queue-mode":"lazy"}' --apply-to queue
上述內容就是RabbitMQ存儲原理和隊列結構是什么,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。