Ezreal 书架 Ezreal 书架
Home
  • 《Go程序员面试笔试宝典》
  • 《RabbitMQ 实战指南》
  • 《深入理解kafka》
  • MySQL45讲
  • 透视HTTP协议
  • 结构化数据的分布式存储系统
  • Raft 共识算法
Home
  • 《Go程序员面试笔试宝典》
  • 《RabbitMQ 实战指南》
  • 《深入理解kafka》
  • MySQL45讲
  • 透视HTTP协议
  • 结构化数据的分布式存储系统
  • Raft 共识算法
  • RabbitMQ简介

  • RabbitMQ 入门

  • 客户端开发向导

  • RabbitMQ 进阶

    • 消息何去何从
    • 过期时间 (TTL)
    • 死信队列
    • 延迟队列
    • 优先级队列
    • RPC 实现
    • 持久化
    • 生产者确认
    • 消费端要点介绍
    • 消息传输保障
    • 小结
  • RabbitMQ 管理

  • RabbitMQ实战指南
  • RabbitMQ 进阶
ezreal_rao
2023-04-07

持久化

"持久化" 这个词汇在前面的篇幅中有多次提及,持久化可以提高 RabbitMQ 的可靠性,以防在异常情况 (重启、关闭、右机等) 下的数据丢失 。本节针对这个概念做一个总结。 RabbitMQ 的持久化分为三个部分:交换器的持久化、队列的持久化和消息的持久化 。

交换器的持久化是通过在声明队列是将 durable 参数置为 true 实现的,详细可以参考 3.2.1 节。如果交换器不设置持久化,那么在 RabbitMQ 服务重启之后,相关的交换器元数据会丢失, 不过消息不会丢失,只是不能将消息发送到这个交换器中了。对一个长期使用的交换器来说,建议将其置为持久化的。

队列的持久化是通过在声明队列时将 durable 参数置为 true 实现的,详细内容可以参考 3.2.2 节 。 如果队列不设置持久化,那么在 RabbitMQ 服务重启之后,相关队列的元数据会丢失,此时数据也会丢失。正所谓 "皮之不存,毛将焉附",队列都没有了,消息又能存在哪里呢?

队列的持久化能保证其本身的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失。要确保消息不会丢失,需要将其设置为持久化。通过将消息的投递模式 (BasicProperties 中的 deliveryMode 属性) 设置为 2 即可实现消息的持久化。前面示例中多次提及的 MessageProperties.PERSISTENT_TEXT_PLAIN 实际上是封装了这个属性:

public static final BasicProperties PERSISTENT TEXT PLAIN new BasicProperties(
    "text/plain", 
    null, null, 2, //lldeliveryMode 
    0, null, null, null, null, null, null, null, null, null);
1
2
3
4

更多发送消息的详细内容可以参考 3.3 节。

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

注意要点:

可以将所有的消息都设直为持久化,但是这样会严重影响 RabbitMQ 的性能 (随机)。写入磁盘的速度比写入内存的速度慢得不只一点点。对于可靠性不是那么高的消息可以不采用持久化处理以提高整体的吞吐量。在选择是否要将消息持久化时,需要在可靠性和吐吞量之间做一个权衡。

将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?答案是否定的 。

首先从消费者来说,如果在订阅消费队列时将 autoAck 参数设置为 true ,那么 当消费者接收到相关消息之后,还没来得及处理就看机了,这样也算数据丢失。这种情况很好解决,将 autoAck 参数设置为 false , 并进行手动确认,详细可以参考 3.5 节 。

其次,在持久化的消息正确存入 RabbitMQ 之后,还需要有一段时间 (虽然很短,但是不可忽视) 才能存入磁盘之中。 RabbitMQ 并不会为每条消息都进行同步存盘 (调用内核的 fsyncl 方法) 的处理,可能仅仅保存到操作系统缓存之中而不是物理磁盘之中。如果在这段时间内 RabbitMQ 服务节点发生了岩机、重启等异常情况,消息保存还没来得及落盘,那么这些消息将会丢失。

这个问题怎么解决呢?这里可以引入 RabbitMQ 的镜像队列机制 (详细参考 9.4 节),相当于配置了副本,如果主节点 (master) 在此特殊时间内挂掉,可以自动切换到从节点 (slave) , 这样有效地保证了高可用性,除非整个集群都挂掉。虽然这样也不能完全保证 RabbitMQ 消息不丢失,但是配置了镜像队列要比没有配置镜像队列的可靠性要高很多,在实际生产环境中的关键业务队列一般都会设置镜像队列。

还可以在发送端引入事务机制或者发送方确认机制来保证消息己经正确地发送并存储至 RabbitMQ 中,前提还要保证在调用 channel.basicPublish 方法的时候交换器能够将消息正确路由到相应的队列之中。详细可以参考下一节。

fsync 在 Linux 中的意义在于同步数据到存储设备上。大多数块设备的数据都是通过缓存进行的,将数据写到文件上通常将该数据由内核复制到缓存中,如果缓存尚未写满,则不将其排入输出队列上,而是等待其写满或者当内核需要重用该缓存时,再 将该缓存排入输出队列,进而同步到设备上 。 这种策略的好处是减少了磁盘读写次数,不足的地方是降低了文件内容的更新速 度,使其不能时刻同步到存储设备上, 当系统发生故障时,这种机制很有可能导致了文件内容的丢失。因此,内核提供了 fsync 接口,用户可以根据自己的需要通过此接口更新数据到存储设备上。

#mq#rabbitmq#amq
上次更新: 5/9/2023, 10:58:32 AM
RPC 实现
生产者确认

← RPC 实现 生产者确认→

最近更新
01
为什么我的MySQL会抖一下
07-15
02
HTTP 性能优化面面观
07-12
03
WebSocket:沙盒里的 TCP
07-12
更多文章>
Theme by Vdoing | Copyright © 2022-2024 Ezreal Rao | CC BY-NC-SA 4.0
豫ICP备2023001810号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式