我是RabbitMQ的新手。
我已经建立了一个'主题'交换。消费者可以在发布者之后开始。我希望消费者能够接收在他们启动之前已经发送的消息,而这些消息还没有被消费。
使用以下参数设置交换:
exchange_type => 'topic'
durable => 1
auto_delete => 0
passive => 0
使用此参数发布消息:
delivery_mode => 2
消费者使用get()从交换中检索消息。
不幸的是,在任何客户端启动之前发布的任何消息都将丢失。我使用了不同的组合。
我想我的问题是交换机没有保留消息。也许我需要在发布者和队列之间有一个队列。但这似乎不适用于通过密钥路由消息的“主题”交换。
知道我该怎么做。我使用Perl绑定Net :: RabbitMQ(无所谓)和RabbitMQ 2.2.0。
答案 0 :(得分:62)
如果没有可用的连接消费者可以在发布消息时处理消息,则需要一个持久的队列来存储消息。
交换不存储消息,但队列可以存储。令人困惑的部分是交换可以被标记为“持久”,但真正意味着,如果你重新启动你的经纪人,交换本身仍将存在,但它确实不表示发送到该交换的任何消息都会自动保留。
鉴于此,这里有两个选项:
我会选择#1。可能没有很多步骤可以执行,您可以始终编写所需的步骤脚本,以便可以重复这些步骤。此外,如果您的所有消费者都要从同一个队列中拉出来(而不是每个队列都有一个专用队列),那么这实际上是一个最小的管理开销。
队列是可以正确管理和控制的。否则你最终可能会被流氓消费者宣布持久排队,使用它们几分钟,但再也不会。不久之后你会有一个永久增长的队列,没有减少它的大小,以及即将到来的经纪人大灾难。
答案 1 :(得分:18)
如Brian所述,交换机不存储消息,主要负责将消息路由到另一个交换机或队列。如果交换未绑定到队列,则发送到该交换的所有消息都将“丢失”
您不需要在发布者脚本中声明固定客户端队列,因为这可能无法扩展。队列可以由您的发布者动态创建,并使用交换到交换绑定在内部路由。
RabbitMQ支持交换到交换绑定,这将允许拓扑灵活性,解耦和其他好处。您可以在RabbitMQ Exchange to Exchange Bindings [AMPQ]
了解更多信息RabbitMQ Exchange To Exchange Binding
示例Python代码,如果使用队列不存在使用者,则使用持久性创建交换到交换绑定。
#!/usr/bin/env python
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
#Declares the entry exchange to be used by all producers to send messages. Could be external producers as well
channel.exchange_declare(exchange='data_gateway',
exchange_type='fanout',
durable=True,
auto_delete=False)
#Declares the processing exchange to be used.Routes messages to various queues. For internal use only
channel.exchange_declare(exchange='data_distributor',
exchange_type='topic',
durable=True,
auto_delete=False)
#Binds the external/producer facing exchange to the internal exchange
channel.exchange_bind(destination='data_distributor',source='data_gateway')
##Create Durable Queues binded to the data_distributor exchange
channel.queue_declare(queue='trade_db',durable=True)
channel.queue_declare(queue='trade_stream_service',durable=True)
channel.queue_declare(queue='ticker_db',durable=True)
channel.queue_declare(queue='ticker_stream_service',durable=True)
channel.queue_declare(queue='orderbook_db',durable=True)
channel.queue_declare(queue='orderbook_stream_service',durable=True)
#Bind queues to exchanges and correct routing key. Allows for messages to be saved when no consumer is present
channel.queue_bind(queue='orderbook_db',exchange='data_distributor',routing_key='*.*.orderbook')
channel.queue_bind(queue='orderbook_stream_service',exchange='data_distributor',routing_key='*.*.orderbook')
channel.queue_bind(queue='ticker_db',exchange='data_distributor',routing_key='*.*.ticker')
channel.queue_bind(queue='ticker_stream_service',exchange='data_distributor',routing_key='*.*.ticker')
channel.queue_bind(queue='trade_db',exchange='data_distributor',routing_key='*.*.trade')
channel.queue_bind(queue='trade_stream_service',exchange='data_distributor',routing_key='*.*.trade')
答案 2 :(得分:0)
从 RabbitMQ Tutorials docs 开始,您需要将 queue
和 messages
标记为持久(以下代码为 C# 版本。使用其他语言,您可以更喜欢here)。
queue
能够在 RabbitMQ
节点重启后继续存在。为此,我们需要将其声明为持久的:channel.QueueDeclare(queue: "hello",
durable: true,
....);
IBasicProperties.SetPersistent
设置为 true。var properties = channel.CreateBasicProperties();
properties.Persistent = true;