(1)内存类型 MQ 节点将队列等运行状态数据不写硬盘,不影响业务数据持久化

内存节点(RAM 节点)的特点

  1. 运行时状态

    • 内存节点仅将运行时状态(如交换器、队列、绑定、虚拟主机、用户和策略的定义)存储在内存中,不会将其写入磁盘。
    • 如果内存节点崩溃或重启,这些运行时状态会丢失,需要从磁盘节点或其他节点恢复。
  2. 业务数据(消息)

    • 消息的存储方式(是否持久化)由消息的 delivery-mode 属性决定,而不是节点类型。
    • 如果消息的 delivery-mode = 2(持久化),即使是在内存节点上,消息也会被写入磁盘。
    • 如果消息的 delivery-mode = 1(非持久化),消息仅存储在内存中,节点类型不会影响这一点。

磁盘节点(Disk 节点)的特点

  1. 运行时状态

    • 磁盘节点将运行时状态存储在内存和磁盘中,确保即使节点重启,这些状态也不会丢失。
  2. 业务数据(消息)

    • 同样,消息的存储方式由 delivery-mode 属性决定,与节点类型无关。

总结

  • 内存节点磁盘节点的区别仅在于运行时状态的存储方式,不会直接影响业务数据(消息)的存储。
  • 消息的持久化由 delivery-mode 属性控制,无论是内存节点还是磁盘节点,持久化消息都会被写入磁盘。
  • 如果使用内存节点,需要注意运行时状态的丢失风险,尤其是在集群环境中,建议至少有一个磁盘节点来保存集群的运行时状态。

(2)关于 DURABLE,只是影响队列是否存在,与其业务数据持久化无关

是的,你的理解是正确的。在 RabbitMQ 中,durable 属性仅影响队列本身的定义是否在 RabbitMQ 服务器重启后仍然存在,而与队列内部的数据(消息)是否持久化无关

durable 属性的作用

  1. 队列的持久化

    • durable=True 时,队列的定义会被持久化到磁盘。即使 RabbitMQ 服务器重启,队列仍然会存在。
    • durable=False 时,队列的定义仅存储在内存中。如果 RabbitMQ 服务器重启,队列会被删除。
  2. 与消息持久化的区别

    • durable 属性仅影响队列的定义,不涉及队列中消息的存储方式
    • 消息是否持久化由消息的 delivery-mode 属性决定:

      • delivery-mode=1:消息非持久化,仅存储在内存中。
      • delivery-mode=2:消息持久化,会被写入磁盘。

使用场景

  • durable=True

    • 适用于需要长期存在的队列,例如任务队列或消息队列,确保队列定义在 RabbitMQ 重启后仍然可用。
    • 即使队列是持久的,队列中的消息仍然需要单独设置为持久化(delivery-mode=2)才能确保消息不丢失。
  • durable=False

    • 适用于临时队列,例如 RPC 风格的应用程序,队列的生命周期与消费者绑定,消费者断开后队列可以自动删除。

注意事项

  • 如果希望消息在 RabbitMQ 重启后仍然存在,必须同时满足以下两个条件:

    1. 队列是持久的(durable=True)。
    2. 消息是持久的(delivery-mode=2)。
  • 如果只设置了 durable=True 而没有设置 delivery-mode=2,队列定义会保留,但消息可能会丢失。

总结

durable 属性仅控制队列定义的持久化,与队列内部消息的存储方式无关。为了确保消息在 RabbitMQ 重启后不丢失,需要同时设置队列为持久化(durable=True)和消息为持久化(delivery-mode=2)。

(3)关于如何不落盘业务数据,需要消息中指定 delivery-mode 为 2

delivery-mode 是 AMQP 协议中定义的一个消息属性,用于指示 RabbitMQ 如何处理消息的存储和持久化。它有两个可能的值:

  1. delivery-mode = 1

    • 这是默认值,表示消息是非持久化的。
    • RabbitMQ 会将消息保留在内存中,不会将其写入磁盘。
    • 如果 RabbitMQ 重启,这些非持久化的消息将会丢失。
  2. delivery-mode = 2

    • 表示消息是持久化的。
    • RabbitMQ 会将消息写入磁盘,确保即使 RabbitMQ 重启,消息仍然会保留在队列中。
    • 这种模式提供了更高的可靠性,但可能会影响性能,因为磁盘 I/O 比内存 I/O 慢。

使用场景

  • delivery-mode = 1:适用于对消息丢失不敏感的场景,例如实时日志或临时数据,可以最大限度地减少延迟。
  • delivery-mode = 2:适用于需要确保消息不丢失的场景,例如金融交易或关键业务数据。

性能影响

  • 使用 delivery-mode = 2 时,由于需要将消息写入磁盘,可能会增加发布消息的延迟,尤其是在高并发或 I/O 负载较高的情况下。
  • 如果需要更高的性能,可以结合其他优化技术,例如事务或批量确认。

总结

delivery-mode 是一个重要的消息属性,开发者需要根据业务需求选择合适的模式,以在消息的可靠性和性能之间找到平衡。

(4)影响 mq 性能的很大原因是 HA 模式加上数据持久化

是的,HA 模式(高可用模式)数据持久化是影响 RabbitMQ 性能的两个重要因素。它们虽然提供了更高的可靠性和容错能力,但也会带来额外的开销,从而影响系统的整体性能。

  1. HA 模式对性能的影响

HA 模式通过将队列镜像到多个节点来实现高可用性,但这会引入以下性能开销:

  • 节点间协调

    • 每次发布或消费消息时,RabbitMQ 需要在所有镜像节点之间进行协调,以确保数据一致性。
    • 镜像节点越多,协调的开销越大,延迟也会增加。
  • 网络开销

    • 镜像节点之间的数据同步需要通过网络传输,可能会增加网络带宽的消耗。
  • 资源消耗

    • 每个镜像节点都需要存储队列的完整副本,这会增加内存和磁盘的使用量。
  1. 数据持久化对性能的影响

数据持久化通过将消息写入磁盘来确保消息在 RabbitMQ 重启后不会丢失,但这也会带来以下性能问题:

  • 磁盘 I/O 开销

    • 每次持久化消息时,RabbitMQ 都需要将消息写入磁盘,而磁盘 I/O 的速度远低于内存操作。
    • 在高并发场景下,频繁的磁盘写入可能成为性能瓶颈。
  • 延迟增加

    • 持久化操作会增加消息发布的延迟,尤其是在磁盘 I/O 负载较高的情况下。
  1. HA 模式 + 数据持久化的综合影响

当 HA 模式和持久化同时启用时,性能影响会进一步加剧:

  • 双重写入开销

    • 消息不仅需要写入本地磁盘,还需要同步到所有镜像节点。
  • 双重协调开销

    • 持久化操作和镜像节点之间的同步都需要额外的协调,这会增加系统的复杂性。
  • 资源消耗倍增

    • 每个镜像节点都需要存储持久化消息的副本,这会显著增加内存和磁盘的使用量。
  1. 优化建议

为了在可靠性和性能之间找到平衡,可以考虑以下优化措施:

  • 合理配置 HA 模式

    • 根据业务需求,选择适当的镜像节点数量。通常,2-3 个镜像节点足以满足大多数场景的高可用性需求。
  • 选择性持久化

    • 仅对关键消息启用持久化(delivery-mode=2),对非关键消息使用非持久化(delivery-mode=1)。
  • 优化磁盘性能

    • 使用高性能的 SSD 磁盘,以减少持久化操作的延迟。
  • 集群设计

    • 将生产者和消费者直接连接到其队列所在的节点,减少网络传输的开销。
  • 监控和调优

    • 定期监控 RabbitMQ 的性能指标(如消息速率、延迟、资源使用率),并根据实际情况进行调整。

总结

HA 模式和持久化是 RabbitMQ 提供高可靠性的重要特性,但它们会显著影响性能。在实际应用中,需要根据业务需求权衡可靠性和性能,并通过合理的配置和优化来最大限度地减少性能损失。

(5)设置 delivery-mode 为 2 有几种模式

在 RabbitMQ 中,设置 delivery-mode 为 2(即持久化消息)可以通过以下几种方式实现:

  1. 在消息发布时设置

在发布消息时,通过设置消息的 BasicProperties 来指定 delivery-mode 为 2。以下是不同编程语言中的实现示例:

Java(使用 RabbitMQ Java 客户端)

AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
    .deliveryMode(2) // 设置为持久化
    .build();
channel.basicPublish(exchange, routingKey, properties, message.getBytes());

Python(使用 Pika 库)

properties = pika.BasicProperties(delivery_mode=2)  # 设置为持久化
channel.basic_publish(exchange='exchange_name',
                      routing_key='routing_key',
                      body='message_body',
                      properties=properties)

Node.js(使用 amqplib 库)

const properties = { deliveryMode: 2 }; // 设置为持久化
channel.publish('exchange_name', 'routing_key', Buffer.from('message_body'), properties);
  1. 在队列声明时设置

虽然 delivery-mode 是消息级别的属性,但可以通过声明持久化队列(durable=True)来确保队列本身在 RabbitMQ 重启后仍然存在。持久化队列与持久化消息通常结合使用,以实现完整的消息可靠性。

Java

boolean durable = true; // 设置为持久化队列
channel.queueDeclare("queue_name", durable, false, false, null);

Python

channel.queue_declare(queue='queue_name', durable=True)  # 设置为持久化队列

Node.js

channel.assertQueue('queue_name', { durable: true }); // 设置为持久化队列
  1. 通过策略(Policy)设置

RabbitMQ 支持通过策略(Policy)为队列或交换器设置默认的 delivery-mode。这种方式可以全局控制消息的持久化行为。

设置策略

rabbitmqctl set_policy my_policy "^my_queue$" '{"delivery-mode":2}' --apply-to queues

解释

  • my_policy:策略名称。
  • ^my_queue$:匹配的队列名称(支持正则表达式)。
  • {"delivery-mode":2}:将匹配队列的消息默认设置为持久化。
  • --apply-to queues:策略应用于队列。
  1. 通过管理界面设置

RabbitMQ 的管理界面(Management Plugin)也支持通过策略设置 delivery-mode

步骤

  1. 打开 RabbitMQ 管理界面(通常是 http://localhost:15672)。
  2. 导航到 Policies 选项卡。
  3. 点击 Add a new policy
  4. Pattern 中输入队列名称(支持正则表达式)。
  5. Definition 中添加 delivery-mode 为 2。
  6. 点击 Add policy 保存。

总结

设置 delivery-mode 为 2 的主要方式包括:

  1. 在消息发布时设置:通过 BasicProperties 指定。
  2. 在队列声明时设置:通过 durable=True 声明持久化队列。
  3. 通过策略设置:使用 RabbitMQ 的策略功能全局控制。
  4. 通过管理界面设置:在 RabbitMQ 管理界面中配置策略。

根据具体需求选择合适的方式,通常建议在消息发布时显式设置 delivery-mode,以确保消息的持久化行为符合预期。

最后修改:2025 年 02 月 24 日
如果觉得我的文章对你有用,请随意赞赏