Rabbitmq 如何从连接以外的其他通道恢复未确认的AMQP消息';他自己的?

Rabbitmq 如何从连接以外的其他通道恢复未确认的AMQP消息';他自己的?,rabbitmq,celery,amqp,pika,celeryd,Rabbitmq,Celery,Amqp,Pika,Celeryd,似乎我让rabbitmq服务器运行的时间越长,未确认的消息就越麻烦。我很想再问他们一次。实际上,似乎有一个amqp命令来执行此操作,但它仅适用于您的连接正在使用的通道。我构建了一个小的pika脚本,至少可以尝试一下,但我要么缺少了一些东西,要么无法通过这种方式完成(使用rabbitmqctl如何?) 未确认的消息是通过网络发送给消费者但尚未确认或拒绝的消息,但消费者尚未关闭其最初接收消息的通道或连接。因此,代理无法确定消费者是否只是花了很长时间来处理这些消息,或者是否忘记了这些消息。因此,在消费

似乎我让rabbitmq服务器运行的时间越长,未确认的消息就越麻烦。我很想再问他们一次。实际上,似乎有一个amqp命令来执行此操作,但它仅适用于您的连接正在使用的通道。我构建了一个小的pika脚本,至少可以尝试一下,但我要么缺少了一些东西,要么无法通过这种方式完成(使用rabbitmqctl如何?)


未确认的消息是通过网络发送给消费者但尚未确认或拒绝的消息,但消费者尚未关闭其最初接收消息的通道或连接。因此,代理无法确定消费者是否只是花了很长时间来处理这些消息,或者是否忘记了这些消息。因此,在消费者死亡或他们得到确认或拒绝之前,它使他们处于未确认状态


因为这些消息在将来仍然可以由最初消费它们的仍然活着的消费者有效地处理,所以(据我所知)您不能将另一个消费者插入到组合中,并尝试对它们做出外部决策。您需要让您的消费者在处理每条消息时做出决定,而不是让旧消息未确认。

如果消息未确认,则只有两种方法可以让它们返回队列:

  • basic.nack

    此命令将使消息放回队列并重新传递

  • 断开与代理的连接

    此操作将强制将此通道中所有未确认的消息放回队列

  • 注意:basic.recover将尝试在同一频道(向同一消费者)上重新发布未经确认的消息,这有时是所需的行为


    真正的问题是:为什么这些消息没有得到确认

    可能导致未确认消息的情况:

  • 消费者获取了太多的消息,但处理和确认它们的速度不够快

    解决方案:根据需要预取尽可能少的消息

  • Buggy client library(我目前在pika 0.9.13中遇到了这个问题。如果队列中有很多消息,一定数量的消息会被卡住而无法确认,甚至在数小时之后

    解决方案:我必须重新启动消费者几次,直到所有未确认的消息从队列中消失


  • 一旦所有工人/消费者停止,所有未确认的消息将进入就绪状态

    通过在
    ps aux
    输出上使用
    grep
    确认,并在发现时停止/杀死所有工人,以确保停止所有工人


    如果您使用supervisor(显示为worker已停止)管理worker,则可能需要检查是否存在僵尸。supervisor报告要停止的worker,但在ps aux输出上显示为灰色时,您仍会发现僵尸进程正在运行。杀死僵尸进程将使消息返回就绪状态。

    因此必须使用basic.recover由消费者领导?我正在使用celeryd管理连接。可能会使用celeryctl将恢复命令发送到响应较差的队列(如果您熟悉的话…)@请允许我对您使用芹菜表示哀悼。芹菜开发人员根本不了解AMQP,并且已经创建了一个严重损坏的实现。您需要做出选择,要么放弃芹菜并正确执行AMQP,要么停止将AMQP与芹菜一起使用,改为使用一些简单的东西,如Redis。我选择放弃芹菜并继续使用AMQP。这很简单起诉书。如果你不介意我问,芹菜的AMQP实施没有得到正确执行怎么办?我同意,我想听听你为什么认为芹菜坏得这么厉害。芹菜被广泛使用,这是我第一次听到这种抱怨。你能解决这个问题吗?所以答案可能有什么需要取决于你为什么这么做其他频道是否仍有未确认的消息。僵尸频道。不是dup,因为本主题是关于其他频道中的消息,而不是频道本身。是否报告了您与pika的问题?您能否提供一个链接?这是一个python递归限制。关于不能递归>1000次,这是pika 0.9.13显然发生了什么。在0.9.14中看不到它。最终找到了报告问题的位置:您还可以使用RabbitMQ管理控制台确定rabbit连接是否被僵尸进程阻塞,如下所述:
    import pika
    
    credentials = pika.PlainCredentials('***', '***')
    parameters = pika.ConnectionParameters(host='localhost',port=5672,\
        credentials=credentials, virtual_host='***')
    
    def handle_delivery(body):
        """Called when we receive a message from RabbitMQ"""
        print body
    
    def on_connected(connection):
        """Called when we are fully connected to RabbitMQ"""
        connection.channel(on_channel_open)    
    
    def on_channel_open(new_channel):
        """Called when our channel has opened"""
        global channel
        channel = new_channel
        channel.basic_recover(callback=handle_delivery,requeue=True)    
    
    try:
        connection = pika.SelectConnection(parameters=parameters,\
            on_open_callback=on_connected)    
    
        # Loop so we can communicate with RabbitMQ
        connection.ioloop.start()
    except KeyboardInterrupt:
        # Gracefully close the connection
        connection.close()
        # Loop until we're fully closed, will stop on its own
        connection.ioloop.start()