存储机制:
1 持久化消息也会在内存中保存一份,当内存紧张的时候,将其从内存中移除
2 非持久化的消息,一般会保存在内存中。当内存紧张时,将其置换到硬盘中
持久层包含两部分:
1 队列索引
2 消息存储
队列索引维护落地消息的信息:1 存储地点 2 消息是否已经交给消费者 3 消息是否已经被ack
每个队列都有一个与其对应的队列索引。
消息存储以 键值对方式存储消息,被所有队列共享。
较小的消息会直接存储在队列索引中。
较大的消息则会存储在消息存储中
索引以段文件进行存储,持久化的消息索引也需要在内存中维护索引段文件,加快响应速度
消息文件以追加方式存储:顺序写,提高存储速度
兔子MQ会在ETS中记录索引文件与消息文件的相关信息
进行消息删除时,只是在ETS文件中删除消息,而消息文件的删除执行懒删除,当垃圾数据达到一定数目50%以上进行清理。此时可以讲两个文件合并为一个文件,并更新ETS文件信息。。。。不用更新索引文件信息?
队列分为两大队列
1 rabbit_amqqueue_process队列
处理接受生产者的消息,向消费者发送消息,处理消息确认等。
2 backing_queue
存储消息,并向rabbit_amqqueue_process提供接口调用。
无论是否持久化的消息。其在队列中不是不变的 而是随着系统状态变化而变动的。
消息可处于以下四种状态:
1 消息内容及消息索引均在内存中
2 消息内容在磁盘,消息索引在内存中
3 消息内容在磁盘,消息索引在内存及硬盘中都有
4 消息内容及索引都在硬盘中
对于未使用优先队列以及镜像的队列。backing_queue的默认实现是 rabbit_variable_queue
其内部通过5个子队列Q1 Q2 Delta Q3 Q4 体现消息的四种状态
Q1 Q4 :状态1
Q2 Q3:状态2,3
Delta:状态4
消息会按照Q1 Q2 Delta Q3 Q4的状态进行流动
向消费者推消息时,
先查Q4 如有消息 返回该消息
如无消息
查Q3
如无消息,返回队列为空
如有消息,
a 取出该消息
b 判断Q3和Delta的长度,
如为空,判定Q2 Delta Q3 Q4皆为空,将Q1直接转移到Q4
如Q3为空而Delta不为空,将Delta中数据转移到Q3中,判定Delta中数据是否完全转移
完全转移,将Q2中数据一起转移到Q3,
未完全转移,仅转移Delta中数据