web-dev-qa-db-ja.com

RabbitMQおよびチャネルと接続の関係

RabbitMQ Java client には次の概念があります。

  • Connection-RabbitMQサーバーインスタンスへの接続
  • Channel-???
  • コンシューマスレッドプール-RabbitMQサーバーキューからメッセージを消費するスレッドのプール
  • キュー-FIFO順序でメッセージを保持する構造

私は関係を理解し​​ようとしています、さらに重要なのは、それらの間の関連付けです。

  1. Channelが何であるかはまだわかりませんが、これはあなたがパブリッシュして消費する構造であり、オープン接続から作成されるという事実を除いてです。誰かが「チャンネル」が何を表しているのかを説明してくれると、いくつかのことがわかりやすくなります。
  2. チャネルとキューの関係は何ですか?同じチャネルを使用して複数のキューと通信できますか、それとも1:1である必要がありますか?
  3. キューとコンシューマープールの関係は何ですか?複数のコンシューマーを同じキューにサブスクライブできますか?同じコンシューマーで複数のキューを使用できますか?または、関係は1:1ですか?

ここで助けてくれてありがとう!

153
user1768830
  1. Connectionは、メッセージブローカーへの実際のTCP接続を表しますが、Channelはその内部の仮想接続(AMPQ接続)です。このようにして、TCP接続でブローカーをオーバーロードすることなく、アプリケーション内で必要な数の(仮想)接続を使用できます。

  2. すべてに1つのChannelを使用できます。ただし、複数のスレッドがある場合は、スレッドごとに異なるChannelを使用することをお勧めします。

    JavaクライアントAPIガイドのチャネルスレッドセーフティ

    チャネルインスタンスは、複数のスレッドで安全に使用できます。チャンネルへのリクエストはシリアル化され、一度に1つのスレッドのみがチャンネルでコマンドを実行できます。それでも、アプリケーションは、複数のスレッド間で同じチャネルを共有するのではなく、スレッドごとにチャネルを使用することを選択する必要があります。

    ChannelQueueの間に直接の関係はありません。 Channelは、AMQPコマンドをブローカーに送信するために使用されます。これはキューの作成などの場合がありますが、これらの概念は結び付けられていません。

  3. Consumerは、コンシューマスレッドプールから割り当てられた独自のスレッドで実行されます。複数のコンシューマーが同じキューにサブスクライブしている場合、ブローカーはラウンドロビンを使用してそれらの間でメッセージを均等に配信します。 チュートリアル2: "作業キュー" を参照してください。

    同じConsumerを複数のキューに接続することもできます。消費者はコールバックとして理解できます。これらは、コンシューマがバインドされているキューにメッセージが到着するたびに呼び出されます。 Java Clientの場合、各コンシューマにはhandleDelivery(...)メソッドがあり、これはコールバックメソッドを表します。通常は、DefaultConsumerをサブクラス化し、handleDelivery(...)をオーバーライドします。注:同じConsumerインスタンスを複数のキューにアタッチすると、このメソッドは異なるスレッドによって呼び出されます。そのため、必要に応じて同期に注意してください。

173
Bengt

ここでは、AMQPプロトコルが「内部で」行うことを概念的によく理解しておくと役立ちます。 AMQP 0.9.1が展開することを選択したドキュメントとAPIは、これを特に混乱させるため、質問自体は多くの人が取り組まなければならないものです。

TL; DR

connectionは、AMQPサーバーとの物理的にネゴシエートされたTCPソケットです。適切に実装されたクライアントには、アプリケーションごとにこれらのいずれかがあり、スレッドセーフで、スレッド間で共有可能です。

channelは、接続上の単一のアプリケーションセッションです。スレッドには、これらのセッションが1つ以上あります。 AMQPアーキテクチャ0.9.1では、これらのスレッドはスレッド間で共有されないため、作成したスレッドが終了したらクローズ/破棄する必要があります。また、さまざまなプロトコル違反が発生すると、サーバーによって閉じられます。

consumerは、特定のチャネル上の「メールボックス」の存在を表す仮想構造です。コンシューマを使用すると、特定のキューからそのチャネルエンドポイントにメッセージをプッシュするようブローカーに指示します。

接続の事実

まず、他の人が正しく指摘しているように、connectionは、サーバーへの実際のTCP接続を表すオブジェクトです。接続はAMQPのプロトコルレベルで指定され、ブローカーとのすべての通信は1つ以上の接続を介して行われます。

  • これは実際のTCP接続であるため、IPアドレスとポート番号があります。
  • プロトコルパラメーターは、接続のセットアップの一部としてクライアントごとにネゴシエートされます(handshakeと呼ばれるプロセス)。
  • 長寿命;接続の閉鎖がプロトコル設計の一部である場合はほとんどありません。
  • OSIの観点からは、おそらく レイヤー6
  • TCP自体にはこれを行うものが含まれていないため、接続状態を監視するようにハートビートを設定できます。
  • 基礎となるTCPソケットへの読み取りと書き込みを管理する専用のスレッドを用意することが最善です。すべてではないにしても、ほとんどの場合、RabbitMQクライアントはこれを行います。その点で、それらは一般にスレッドセーフです。
  • 比較的言えば、接続は(ハンドシェイクにより)作成するのに「高価」ですが、実際には、これは実際には問題ではありません。ほとんどのプロセスでは、実際に必要な接続オブジェクトは1つだけです。ただし、単一のスレッド/ソケットが提供できるスループットよりも多くのスループットが必要な場合は、プール内の接続を維持できます(現在のコンピューティングテクノロジーとは異なります)。

チャンネルの事実

Channelは、RabbitMQブローカーと通信するためにアプリの各部分に対して開かれるアプリケーションセッションです。単一の接続で動作し、ブローカーとのセッションを表します。

  • アプリケーションロジックの論理部分を表すため、各チャネルは通常、独自のスレッドに存在します。
  • 通常、アプリによって開かれたすべてのチャネルは、単一の接続を共有します(接続上で動作する軽量セッションです)。接続はスレッドセーフなので、これで問題ありません。
  • ほとんどのAMQP操作はチャネルを介して行われます。
  • OSIレイヤーの観点からは、チャネルはおそらく レイヤー7 の周りにあります。
  • チャネルは一時的であるように設計されています; AMQPの設計の一部は、エラー(通常、既存のキューを削除する前に異なるパラメーターでキューを再宣言する)に応答してチャネルが通常閉じられることです。
  • これらは一時的なものであるため、アプリでチャネルをプールしないでください。
  • サーバーは整数を使用してチャネルを識別します。接続を管理するスレッドは、特定のチャネルのパケットを受信すると、この番号を使用して、パケットが属するチャネル/セッションをブローカーに通知します。
  • チャネルはスレッド間で共有する意味がないため、一般的にスレッドセーフではありません。 ブローカーを使用する必要がある別のスレッドがある場合、新しいチャネルが必要です。

消費者の事実

コンシューマは、AMQPプロトコルによって定義されたオブジェクトです。これはチャネルでも接続でもありません。代わりに、特定のアプリケーションがメッセージをドロップするための一種の「メールボックス」として使用するものです。

  • 「コンシューマを作成する」とは、connectionを介してchannelを使用してブローカーにメッセージをプッシュすることを伝えることを意味します。そのチャンネルを介して。応答として、ブローカーは、チャンネルにconsumerがあることを登録し、メッセージのプッシュを開始します。
  • 接続を介してプッシュされた各メッセージは、チャネル番号消費者番号の両方を参照します。このようにして、接続管理スレッド(この場合、Java AP​​I内)はメッセージの処理方法を認識しています。その後、チャネル処理スレッドはメッセージの処理方法も認識します。
  • コンシューマー実装は、文字通りアプリケーション固有であるため、最も多様です。私の実装では、コンシューマーを介してメッセージが到着するたびにタスクをスピンオフすることにしました。したがって、接続を管理するスレッド、チャネル(および拡張機能により、コンシューマー)を管理するスレッド、およびコンシューマーを介して配信される各メッセージの1つ以上のタスクスレッドがありました。
  • connectionを閉じると、接続上のすべてのチャネルが閉じられます。 channelを閉じると、チャネル上のすべてのコンシューマが閉じられます。消費者をcancelすることも可能です(チャネルを閉じずに)。 3つのことのいずれかを行うことが理にかなっている場合はさまざまです。
  • 通常、AMQPクライアントでのコンシューマの実装は、他のスレッドまたはコード(パブリッシングを含む)のアクティビティとの競合を避けるために、コンシューマに1つの専用チャネルを割り当てます。

コンシューマスレッドプールの意味では、Javaクライアントは、クライアントが実行するようにプログラムしたものと似た動作をしていると考えられます(私のものは.Netクライアントに基づいていましたが、大幅に変更されていました)。

41
theMayer

AMQPモデルのすべての側面を説明するこの記事を見つけましたが、そのうちの1つはチャネルです。私の理解を締めくくるのに非常に役立ちました

https://www.rabbitmq.com/tutorials/amqp-concepts.html

一部のアプリケーションでは、AMQPブローカーへの複数の接続が必要です。ただし、多くのTCP接続を同時に開いたままにすると、システムリソースが消費され、ファイアウォールの構成が難しくなるため、望ましくありません。 AMQP 0-9-1接続は、「単一のTCP接続を共有する軽量接続」と考えることができるチャネルと多重化されます。

処理に複数のスレッド/プロセスを使用するアプリケーションの場合、スレッド/プロセスごとに新しいチャネルを開き、それらの間でチャネルを共有しないことは非常に一般的です。

特定のチャネルでの通信は別のチャネルでの通信とは完全に分離されているため、すべてのAMQPメソッドは、メソッドが対象とするチャネル(したがって、たとえば、どのイベントハンドラーを呼び出す必要があるか)を判別するためにクライアントが使用するチャネル番号も保持します。

19
CamW