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中).

 

 

 

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