首先,先讲一下背景: 持久化和短暂消息都可以写入磁盘.持久化消息一旦到达队列,就会写入磁盘,而短暂消息只在内存压力较大被赶出内存时才会写入磁盘.持久化消息在内存紧张释放内存时,依然也会存在内存中. 持久层指的是存储这两种类型消息到磁盘的机制.
在本页中,我们说的队列是指无镜像队列或master队列或slave队列. 队列镜像会发生以上的持久化.
持久层有两个组件: 队列索引和消息存储.队列索引负责维护消息在队列的位置,以及是否被投递,是否应答的信息. 因此,每个队列都有一个队列索引。
消息存储是消息的key-value存储, 由服务器中的所有队列共享.消息(消息体, 消息属性或消息头)可直接存储于队列索引,也可以写到消息存储中.在技术上有两个消息存储(一个暂时的和一个持久的消息),但他们通常一起被被认为是“消息存储”。
内存成本在内存压力下,持久层试图尽可能多地写入磁盘,并尽可能的从内存中删除。然而有一些事情必须留在内存中:每个队列都会为每个未应答消息维护一些元数据.如果它的目的地是消息存储,则消息本身可以从内存中删除。消息存储需要索引. 默认消息存储索引对于存储中的每个消息会使用少量内存.队列索引中的消息将消息写入队列索引有优点也有缺点.
优点:
消息可在一个操作中(而不是两个)写入磁盘; 对于微小的消息,这可以是一个实质性的增益.写入队列索引的消息不需要消息存储索引中的条目,因此当页出(paged out)时,不需要花费内存成本.缺点:
队列索引在内存中保有固定数量的记录块;如果写入队列索引中的消息不是小消息,那么内存占用也是巨大的.如果一个消息通过一个交换路由到多个队列,则消息将需要写入多个队列索引。如果这样的消息被写入消息存储区,则只有一个副本需要被写入。目的地是队列索引的未应答消息总会保存在内存中.将小消息存储在队列索引中目的是优化,所有其它消息将会写入消息存储.这可以配置项queue_index_embed_msgs_below来配置.默认情况下,序列后大小小于4096字节 (包括属性和头)会存储在队列索引中.
当从磁盘中读取消息时,每个队列索引至少需要在内存中保留一个段文件(segment file). 段文件中包含了16,384个消息. 因此要谨慎如果增加queue_index_embed_msgs_below;小的增加会导致大量的内存使用。
无意中有限的持久性能(Accidentally limited persister performance)持久化有可能表现不佳,因为持久化受限于文件句柄的数目或与它工作的异步线程.在这两种情况下,当您有大量需要同时访问磁盘的队列时,会发生这样的情况。.
太少的文件句柄RabbitMQ 服务器通常受限于它能打开的文件句柄数量(在Unix上,无论如何). 每个运行的网络连接都需要一个文件句柄, 其余的可用于队列使用。如果磁盘访问队列比考虑到网络连接后文件句柄