RabbitMQ持久队列绑定

时间:2019-02-12 16:25:40

标签: python rabbitmq pika

我正在尝试使用RabbitMQ topic交换将发布者的消息可靠地发送给多个消费者。

我已经配置了持久队列(每个使用者一个),并且正在发送持久消息delivery_mode=2。我还将频道设置为confim_delivery,并添加了mandatory=True标志以进行发布。

目前该服务非常可靠,但是如果消息在代理重新启动后停滞不前,则消息丢失给其中一个使用者。 消息发布。

似乎代理可以在重新启动时恢复队列和消息,但是似乎并不能保持使用者和队列之间的绑定。因此,消息仅到达其中一个消费者,而对于出现故障的一个则丢失。

注意:如果在使用方关闭期间代理未遭受重新启动,则消息确实到达了队列,并且使用方使用了消息。它们在队列中正确堆积,并在再次出现时交付给消费者。

编辑-添加消费者代码:

import pika


class Consumer(object):
    def __init__(self, queue_name):
        self.queue_name = queue_name

    def consume(self):
        credentials = pika.PlainCredentials(
             username='myuser', password='mypassword')
        connection = pika.BlockingConnection(
             pika.ConnectionParameters(host='myhost', credentials=credentials))
        channel = connection.channel()
        channel.exchange_declare(exchange='myexchange', exchange_type='topic')
        channel.queue_declare(queue=self.queue_name, durable=True)
        channel.queue_bind(
            exchange='myexchange', queue=self.queue_name, routing_key='my.route')
        channel.basic_consume(
            consumer_callback=self.message_received, queue=self.queue_name)
        channel.start_consuming()

    def message_received(self, channel, basic_deliver, properties, body):
        print(f'Message received: {body}')
        channel.basic_ack(delivery_tag=basic_deliver.delivery_tag)

您可以假设每个消费者服务器执行的操作类似于:

c = Consumer('myuniquequeue')  # each consumer has a permanent queue name
c.consume()

编辑-添加发布者代码:

def publish(message):
    credentials = pika.PlainCredentials(
        username='myuser', password='mypassword')
    connection = pika.BlockingConnection(
        pika.ConnectionParameters(host='myhost', credentials=credentials))
    channel = connection.channel()
    channel.exchange_declare(exchange='myexchange', exchange_type='topic')
    channel.confirm_delivery()
    success = channel.basic_publish(
        exchange='myexchange',
        routing_key='my.route',
        body=message,
        properties=pika.BasicProperties(
            delivery_mode=2,  # make message persistent
        ),
        mandatory=True
    )
    if success:
        print("Message sent")
    else:
        print("Could not send message")
        # Save for sending later

值得一提的是,我自己处理错误情况,这不是我想改进的部分。当我的消息丢失给某些消费者时,流程将进入成功部分

1 个答案:

答案 0 :(得分:0)

在使用者回调方法中使用basic.ack(delivery_tag=basic_deliver.delivery_tag)。该确认告知消费者是否已接收到消息并已对其进行处理。如果为否定确认,则将重新排队该邮件。

编辑#1 为了在代理崩溃期间接收消息,需要分发代理。在RabbitMQ中,这是一个称为“镜像队列”的概念。 Mirrored Queues使您的队列可以在群集中的节点之间复制。如果包含队列的一个节点发生故障,则包含队列的另一个节点将充当您的代理。

要完全理解,请参阅此Mirrored Queues