Q1 と Q2 の 2 つのキューを持つ単一の activemq ブローカーがある状況があります。Activemessaging を使用する 2 つの Ruby ベースのコンシューマがあります。それらをC1とC2と呼びましょう。両方のコンシューマーが各キューをサブスクライブします。各キューにサブスクライブするときに activemq.prefetchSize=1 を設定しています。ack=client も設定しています。
次の一連のイベントを検討してください。
1) 長時間実行ジョブをトリガーするメッセージがキュー Q1 にパブリッシュされます。これを M1 と呼びます。
2) M1 がコンシューマー C1 にディスパッチされ、長い操作が開始されます。
3) 短いジョブをトリガーする 2 つのメッセージがキュー Q2 に発行されます。これらを M2 および M3 と呼びます。
4) M2 は C2 にディスパッチされ、C2 は短時間のジョブを迅速に実行します。
5) C1 がまだ M1 を実行しているにもかかわらず、M3 が C1 にディスパッチされます。prefetchSize=1 が接続ではなくキュー サブスクリプションに設定されているため、C1 にディスパッチできます。したがって、Q1 メッセージが既にディスパッチされているという事実は、1 つの Q2 メッセージのディスパッチを停止しません。
activemessaging コンシューマーはシングルスレッドであるため、最終的には、C1 が M1 の処理を完了するまで、M3 は長時間 C1 を待機します。そのため、コンシューマー C2 がアイドル状態であるにもかかわらず (メッセージ M2 ですぐに終了するため)、M3 は長時間処理されません。
基本的に、Q1 の長いジョブが実行され、Q2 の短いジョブが大量に作成されると、Q2 の短いジョブの 1 つだけがコンシューマーでスタックし、Q1 の長いジョブが完了するのを待機します。
サブスクリプション レベルではなく接続レベルで prefetchSize を設定する方法はありますか? M1 を処理している間、C1 にメッセージをディスパッチしたくありません。もう 1 つの方法は、Q1 の処理専用のコンシューマーを作成してから、Q2 の処理専用の別のコンシューマーを作成することです。しかし、Q1 のメッセージはめったにないので、私はそれをしたくありません。Q1 の専用のコンシューマーは、ほとんどの時間、メモリを拘束してアイドル状態になります。