RabbitMQ:具有主题交换的持久消息

RabbitMQ:具有主题交换的持久消息,rabbitmq,amqp,Rabbitmq,Amqp,我对兔子很陌生 我已经建立了一个“主题”交流。用户可以在发布者之后启动。我希望消费者能够接收在他们上线之前发送的消息,而这些消息还没有被消费 使用以下参数设置exchange: exchange_type => 'topic' durable => 1 auto_delete => 0 passive => 0 使用此参数发布消息: delivery_mode => 2 使用者使用get()从exchange检索消息 不幸的是,在任何客户端启动之前发布的任何消息

我对兔子很陌生

我已经建立了一个“主题”交流。用户可以在发布者之后启动。我希望消费者能够接收在他们上线之前发送的消息,而这些消息还没有被消费

使用以下参数设置exchange:

exchange_type => 'topic'
durable => 1
auto_delete => 0
passive => 0
使用此参数发布消息:

delivery_mode => 2
使用者使用get()从exchange检索消息

不幸的是,在任何客户端启动之前发布的任何消息都将丢失。我使用了不同的组合

我想我的问题是交换不保存消息。也许我需要在发布者和消费者之间建立一个队列。但这似乎不适用于通过密钥路由消息的“主题”交换


我应该如何进行?我使用
Perl
绑定
Net::RabbitMQ
(应该没关系)和
RabbitMQ 2.2.0

如果在消息发布时没有可用的连接消费者来处理消息,则需要一个持久队列来存储消息

exchange不存储消息,但队列可以。令人困惑的是,交换可以标记为“持久”,但真正的意思是,如果重新启动代理,交换本身仍将存在,但这并不意味着发送到该交换的任何消息都会自动持久化

鉴于此,有两种选择:

  • 在启动发布服务器以自己创建队列之前,请执行管理步骤。您可以使用web UI或命令行工具来执行此操作。确保将其创建为持久队列,这样即使没有活动使用者,它也会存储路由到它的任何消息
  • 假设您的消费者在启动时总是声明(并因此自动创建)他们的交换和队列(并且他们声明它们是持久的),只需在启动任何发布服务器之前运行所有消费者至少一次。这将确保正确创建所有队列。然后,您可以关闭消费者,直到他们真正需要,因为队列将持续存储将来路由到他们的任何消息
  • 我会选择1。可能需要执行的步骤不多,您可以始终编写所需步骤的脚本,以便重复这些步骤。另外,如果您的所有消费者都要从同一个队列(而不是每个队列都有一个专用队列)中提取数据,那么这实际上是一个最小的管理开销


    队列是需要适当管理和控制的东西。否则,最终可能会有流氓消费者声明持久队列,使用它们几分钟,但再也不会使用。不久之后,您将拥有一个永久性增长的队列,而队列的大小却没有任何减少,并且即将出现代理灾难。

    正如Brian所提到的,exchange不存储消息,主要负责将消息路由到另一个exchange或队列。如果exchange未绑定到队列,则发送到该exchange的所有消息都将“丢失”

    您不需要在发布服务器脚本中声明固定客户端队列,因为这可能是不可伸缩的。发布者可以动态创建队列,并使用exchange到exchange绑定在内部路由队列

    RabbitMQ支持exchange到exchange绑定,这将允许拓扑灵活性、解耦和其他好处。你可以在这里阅读更多

    示例Python代码,用于在不存在使用队列的使用者时创建具有持久性的exchange到exchange绑定

    #/usr/bin/env python
    进口鼠兔
    导入系统
    连接=pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost'))
    channel=connection.channel()
    #声明所有生产者用于发送消息的条目交换。也可能是外部生产商
    channel.exchange\u declare(exchange='data\u gateway',
    交换\u type='fanout',
    持久的,
    自动删除(错误)
    #声明要使用的处理交换。将消息路由到各种队列。仅供内部使用
    channel.exchange\u declare(exchange='data\u distributor',
    交换_type='topic',
    持久的,
    自动删除(错误)
    #将面向外部/生产商的exchange绑定到内部exchange
    channel.exchange\u bind(destination='data\u distributor',source='data\u gateway')
    ##创建绑定到数据分发服务器exchange的持久队列
    channel.queue\u declare(queue='trade\u db',dustable=True)
    channel.queue\u declare(queue='trade\u stream\u service',durable=True)
    channel.queue\u declare(queue='ticker\u db',dustable=True)
    channel.queue\u declare(queue='ticker\u stream\u service',durable=True)
    channel.queue\u declare(queue='orderbook\u db',dustable=True)
    channel.queue\u declare(queue='orderbook\u stream\u service',durable=True)
    #将队列绑定到交换机并更正路由密钥。允许在没有消费者时保存消息
    channel.queue\u绑定(queue='orderbook\u db',exchange='data\u distributor',routing\u key='*.*.orderbook')
    channel.queue\u绑定(queue='orderbook\u stream\u service',exchange='data\u distributor',routing\u key='*.*.orderbook')
    channel.queue\u bind(queue='ticker\u db',exchange='data\u distributor',routing\u key='*.*.ticker')
    channel.queue\u bind(queue='ticker\u stream\u service',exchange='data\u distributor',routing\u key='*.*.ticker')
    channel.queue\u bind(queue='trade\u db',exchange='data\u distributor',routing\u key='*.*.trade')
    channel.queue\u bind(queue='trade\u stream\u service',exchange='data\u distributor',routing\u key='*.*.trade')
    
    您的案例似乎是“消息持久性”。 从中,您需要将
    队列
    消息
    标记为持久(下面的代码为C版本。对于其他语言,您可以更喜欢)

  • 首先,在Publisher中,您需要确保
    队列
    RabbitMQ
    节点重新启动后仍然有效。为了做到这一点,我们需要宣布其为耐用:
  • 第二,,
    channel.QueueDeclare(queue: "hello",
                         durable: true,
                         ....);
    
    var properties = channel.CreateBasicProperties();
    properties.Persistent = true;