Techioz Blog

RabbitMQ で他のコンシューマが利用可能な場合、コンシューマにメッセージがスタックされる - レールにバニーを使用する

概要

RabbitMQ のキュー メッセージは、他のコンシューマが利用可能な間、スタックされて単一のコンシューマを待機します。

私たちはメッセンジャーサービスとして RabbitMQ を使用しています。バニーを使用して接続を作成し、メッセージを渡すキューを設定します。

Bunny を使用した Rails セットアップでは、1 つのキューがあり、8 人のコンシューマーがそのキューでメッセージをリッスンしているという問題が発生しています。メッセージが受信されると、理想的にはコンシューマをラウンドロビンする必要があります。例: キューに 4 つのメッセージがあり、コンシューマ 1 がメッセージ 1 を取得します。 - コンシューマ 1 はビジーで、コンシューマ 2 はメッセージ 2 を取得します。コンシューマ 2 はビジーで、コンシューマ 3メッセージ 3 を取得します。

しかし、私たちが抱えている問題は、キュー内に 4 つのメッセージがあり、コンシューマ 1 がメッセージ 1 を取得し、コンシューマ 1 はビジーで、コンシューマ 2 ~ 8 は利用可能ですが、メッセージ 2 ~ 4 はキュー内でコンシューマ 1 が利用可能になるのを待っているということです。メッセージを処理します。

たくさんの調査を行ったような気がしますが、メッセージがスタックして単一のコンシューマを待機するのを防ぐ方法がまったくわかりません。

このような経験をした人、またはこの問題を解決する方法について何かアイデアを持っている人はいますか?

conn = Bunny.new(bunny[0])
conn.start
ch = conn.create_channel
q = ch.queue("#{record_queue_name}", :durable => true)
q.subscribe(:manual_ack => true, :arguments => {"x-priority" => 10}, :block => true) do |delivery_info, properties, payload|
ch.acknowledge(delivery_info.delivery_tag, false)

私たちは、メッセージが RabbitMQ に送信されるたびに、コンシューマが先着順でメッセージを取得することを望んでいます。他のメッセージが利用可能なときにビジーなコンシューマを待って複数のメッセージがスタックされるのではありません。

編集: 再現方法: 3 つのコンシューマを同時に起動します。 6 つのメッセージをプッシュスルーします - コンシューマー 1 ~ 3 は現在、キュー内の 3 つのメッセージでビジー状態です。 2 と 3 を再起動します。2 と 3 が再度リッスンすると、コンシューマ 1 を待機しているキューで 3 つのメッセージがまだ待機しています。コンシューマ 2 と 3 はまだ利用可能です。

コンシューマー 1 を再起動します。キューに入れられた 3 つのメッセージが、新しく再起動されたコンシューマー 2 と 3 に最初のサーバーに送られます。

コンシューマが再起動するかどうかに関係なく、メッセージを先着順のサーバーに送信する必要があります。

解決策

RabbitMQ は意図したとおりに動作しています。

コードでは QoS / プリフェッチを設定していないため、RabbitMQ は 6 つのメッセージすべてを最初のコンシューマーに送信します。このコンシューマーはメッセージを確認するのに時間がかかるため (コード内の 45 秒のスリープによってシミュレートされています)、他の 2 つのコンシューマーが何も処理できる間、これらの 6 つは「未確認」状態のままになります。 6 つのメッセージはすべて「Unacked」状態で最初のコンシューマからの ACK を待っているため、他の 2 つのコンシューマを再起動しても効果はありません。

最初のコンシューマを再起動すると、RabbitMQ は接続の切断を検出し、6 つのメッセージをキューに入れて「準備完了」状態にし、(おそらく) 6 つすべてを別のコンシューマに配信します。すると問題が繰り返します。

プリフェッチの設定方法については、この実行可能なコード サンプルを参照してください。プリフェッチが 1 の場合、RabbitMQ は最大でも 1 つのメッセージをコンシューマに配信し、ACK を待ってから別のメッセージをそのコンシューマに配信します。このようにして、メッセージは消費者間で配信されます。