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