消息持久化

消息持久化

当RabbitMQ服务器挂了,它可能就丢失所有队列中的消息和任务。如果你想让RabbitMQ记住当前的状态和内容,就需要通过2件事来确保消息和任务不会丢失:同时将queue和messages标识为durable。

设置了队列和消息的持久化之后,当broker服务重启的之后,消息依旧存在。单只设置队列持久化,重启之后消息会丢失;单只设置消息的持久化,重启之后队列消失,既而消息也丢失。单单设置消息持久化而不设置队列的持久化显得毫无意义。

注意:已经定义的队列,再次定义是无效的!(RabbitMQ不允许重新定义一个已有的队列信息,也就是说不允许修改已经存在的队列的参数。如果你非要这样做,只会返回异常。咋整?

一个快速有效的方法就是重新声明另一个名称的队列,不过这需要修改生产者和消费者的代码,所以,在开发时,最好是将队列名称放到配置文件中。

这时,即使RabbitMQ服务器重启,新队列中的消息也不会丢失。)

消息在正确存入RabbitMQ之后,还需要有一段时间(这个时间很短,但不可忽视)才能存入磁盘之中,RabbitMQ并不是为每条消息都做fsync的处理,可能仅仅保存到cache中而不是物理磁盘上,在这段时间内RabbitMQ broker发生crash, 消息保存到cache但是还没来得及落盘,那么这些消息将会丢失。那么这个怎么解决呢?首先可以引入RabbitMQ的mirrored-queue即镜像队列,这个相当于配置了副本,当master在此特殊时间内crash掉,可以自动切换到slave,这样有效的保障了HA, 除非整个集群都挂掉,这样也不能完全的100%保障RabbitMQ不丢消息,但比没有mirrored-queue的要好很多,很多现实生产环境下都是配置了mirrored-queue的。还有要在producer引入事务机制或者Confirm机制来确保消息已经正确的发送至broker端。

RabbitMQ的可靠性涉及producer端的确认机制、broker端的镜像队列的配置以及consumer端的确认机制,要想确保消息的可靠性越高,那么性能也会随之而降,鱼和熊掌不可兼得,关键在于选择和取舍。

标记为持久化后的消息也不能完全保证不会丢失。虽然已经告诉RabbitMQ消息要保存到磁盘上,但是理论上,RabbitMQ已经接收到生产者的消息,但是还没有来得及保存到磁盘上,服务器就挂了(比如机房断电),那么重启后,RabbitMQ中的这条未及时保存的消息就会丢失。因为RabbitMQ不做实时立即的磁盘同步(fsync)。这种情况下,对于持久化要求不是特别高的简单任务队列来说,还是可以满足的。如果需要更强大的保证,那么你可以考虑使用生产者确认反馈机制。

RabbitMQ消息存储在间隔(几百毫秒)后或者当一个队列处于空闲状态时,将消息持久化到磁盘,以最大限度地减少fsync(2)调用的次数。

持久(persistent)和临时(transient)消息都可以写入磁盘。持久性消息一旦到达队列就会被写入磁盘,而临时消息只会在内存压力下将其从内存中逐出时写入磁盘。

“持久层”(persistence layer)指的是用于将两种类型的消息存储到磁盘的机制。

持久层有两个组件:队列索引(queue index)和消息存储(message store)。

队列索引负责维护关于给定消息在队列中的位置信息,以及它是否已被传递和确认。因此每个队列都有一个队列索引。

消息存储是消息的键值存储,由服务器中的所有队列共享。消息可以直接存储在队列索引中,也可以写入消息存储库。技术上分为两个消息存储器(一个用于临时,一个用于持久消息),但它们通常一起被称做“消息存储”。

内存开销:

每个队列为每个未确认的消息维护一些元数据。如果消息的目标是消息存储,则消息本身可以从内存中删除。

消息存储需要一个索引。默认消息存储索引对存储库中的每条消息使用少量内存。

将非常小的消息作为优化存储在queue index中,而将所有其他消息写入message store。(默认情况下,序列化大小小于4096字节(包括属性和标题)的消息存储在queue index中。)

END

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180725B0958C00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券