web-dev-qa-db-ja.com

接続のチャネル以外のチャネルから未確認のAMQPメッセージを回復するにはどうすればよいですか?

Rabbitmqサーバーを実行し続ける時間が長くなるほど、未確認のメッセージで問題が発生するようです。それらを再度キューに入れたいです。実際、これを行うためのamqpコマンドがあるようですが、これは接続が使用しているチャネルにのみ適用されます。少なくとも試してみるために小さなpikaスクリプトを作成しましたが、何かが足りないか、この方法ではできません(rabbitmqctlではどうですか?)

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()
44
Will Olbrys

未確認のメッセージとは、ネットワークを介して消費者に配信されたが、まだ承認または拒否されていないメッセージですが、その消費者はまだ受信したチャネルまたは接続をまだ閉じていません。したがって、ブローカーは、消費者がそれらのメッセージを処理するのに長い時間をかけているのか、それを忘れているのかを判断できません。そのため、消費者が死亡するか、確認または拒否されるまで、未承認の状態のままになります。

それらのメッセージは、将来それらを最初に消費したまだ生きている消費者によってまだ有効に処理される可能性があるため、(私の知る限り)別の消費者をミックスに挿入して、それらについて外部の決定を試みることはできません。古いメッセージを未確認のままにするのではなく、処理されるたびに各メッセージについて決定するようにコンシューマを修正する必要があります。

64
Brian Kelly

メッセージが確認されない場合、メッセージをキューに戻す方法は2つしかありません。

  1. basic.nack

    このコマンドにより、メッセージはキューに戻され、再配信されます。

  2. ブローカーから切断します

    このアクションにより、このチャネルからのすべての未確認メッセージが強制的にキューに戻されます。

[〜#〜] note [〜#〜]:basic.recoverは、同じチャネルで(同じコンシューマに)不正なメッセージを再発行しようとします。これは時々望ましい動作です。

basic.recoverおよびbasic.nackのRabbitMQ仕様


本当の質問は次のとおりです。なぜメッセージは確認されないのですか?

未確認のメッセージを引き起こす可能性のあるシナリオ:

  1. 消費者が取得するメッセージが多すぎて、十分な速さで処理および確認されない。

    解決策:必要な数のメッセージをプリフェッチします。

  2. バギークライアントライブラリ(現在、pika 0.9.13でこの問題があります。キューに多くのメッセージがある場合、特定の数のメッセージがスタックします。数時間後でも解き放たれます。

    解決策:確認されていないメッセージがすべてキューから削除されるまで、コンシューマを数回再起動する必要があります。

19
IvanD

すべてのワーカー/コンシューマーが停止すると、未確認のメッセージはすべて準備完了状態になります。

ps aux出力でgrepで確認し、見つかった場合はそれらを停止/強制終了して、すべてのワーカーが停止していることを確認します。

スーパーバイザーを使用してワーカーを管理している場合(ワーカーが停止していることを示す)、ゾンビをチェックすることができます。スーパーバイザーはワーカーが停止していると報告しますが、ps aux出力でgrepを実行するとゾンビプロセスが実行されていることがわかります。ゾンビプロセスを強制終了すると、メッセージは準備完了状態に戻ります。

4
Venkat Kotra