RabbitMQとチャネルと接続の関係


176

RabbitMQのJavaクライアントは、次の概念があります。

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

私は関係、そしてもっと重要なことには、それらの間の関連を理解しようとしています。

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

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


この質問への回答により、私はここで質問するのではなく、golangクライアントでこの問題を報告しました。
ブルースアダムス

チャネルは、クライアントとノード間の単一の物理TCP接続を多重化するために使用される論理的な概念です。チャネル番号は、AMQPフレームのメッセージヘッダーに含まれています。
ymas

回答:


196
  1. A Connectionはメッセージブローカーへの実際のTCP接続を表し、a Channelはその内部の仮想接続(AMQP接続)です。この方法では、TCP接続でブローカーに過負荷をかけることなく、アプリケーション内で必要なだけ(仮想)接続を使用できます。

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

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

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

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

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

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


4
ドキュメントから追加するだけです:コンシューマーへのコールバックは、接続によって管理されるスレッドとは別のスレッドでディスパッチされます。これは、コンシューマが、queueDeclare、txCommit、basicCancel、basicPublishなどの接続またはチャネルのブロッキングメソッドを安全に呼び出すことができることを意味します。各チャネルには独自のディスパッチスレッドがあります。チャネルごとに1つのコンシューマーという最も一般的な使用例では、これはコンシューマーが他のコンシューマーを妨げないことを意味します。チャネルごとに複数のコンシューマーがある場合は、長時間実行しているコンシューマーがそのチャネル上の他のコンシューマーへのコールバックのディスパッチを保留する可能性があることに注意してください。
2014

1
同じコンシューマインスタンスを同じチャネルの複数のキューに接続すると、コールバックが同じスレッドでディスパッチされることになります。その場合、同期は必要ありませんか?
フィリップ2014

1つの接続のみを使用して、接続プールの代わりにチャネルのプールを使用できますか?これはメッセージ公開のスループットに影響しますか?
15年

4
このJavaクライアントAPIへの参照は古くなっていると思います。実際、今日の参照はこの回答の引用と直接矛盾しています。今日のリファレンスでは、「チャネルインスタンスはスレッド間で共有してはならない」と述べています。
Edwin Dalorzo 2017年

1
@EdwinDalorzo-最初にドキュメントを書いた人は、チャネル接続の二分法を完全に理解していなかったようです。AMQP 0.9.1の基本的なアーキテクチャーは、チャネルを実際にはセッションとして扱うため、セッションを共有する異なるスレッドは実際にはナンセンスです。それが変更の理由だと思います。
theMayer 2018

53

ここでは、AMQPプロトコルが「内部で」何を行うかについての概念的な理解が役立ちます。AMQP 0.9.1がデプロイすることを選択したドキュメントとAPIはこれを特に混乱させるので、質問自体は多くの人々が取り組む必要のある問題です。

TL; DR

接続は、 AMQPサーバと物理的に交渉TCPソケットです。適切に実装されたクライアントは、アプリケーションごとにこれらの1つを持ち、スレッドセーフであり、スレッド間で共有できます。

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

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

接続の事実

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

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

チャンネルの事実

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

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

消費者情報

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

  • 「コンシューマーの作成」とは、ブローカーに(接続を介したチャネルを使用して)メッセージをそのチャネル経由でプッシュすることを通知することを意味します。それに応じて、ブローカーはチャンネルにコンシューマーがいることを登録し、メッセージをプッシュし始めます。
  • 接続を介してプッシュされる各メッセージは、チャネル番号コンシューマー番号の両方を参照します。このようにして、接続管理スレッド(この場合はJava API内)はメッセージの処理方法を認識します。その後、チャネル処理スレッドはメッセージの処理方法も認識します。
  • 文字どおりアプリケーション固有であるため、コンシューマの実装には最も大きな変動があります。私の実装では、コンシューマー経由でメッセージが到着するたびにタスクをスピンオフすることを選択しました。したがって、私は、接続を管理するスレッド、チャネル(さらにはコンシューマー)を管理するスレッド、そしてコンシューマーを介して配信されるメッセージごとに1つ以上のタスクスレッドを持っていました。
  • 閉会の接続は、接続上のすべてのチャネルを閉じます。閉会チャネルは、チャネル上のすべての消費者を閉じます。(チャンネルを閉じずに)コンシューマをキャンセルすることもできます。3つのことのいずれかを実行することが理にかなっている場合は、さまざまな場合があります。
  • 通常、AMQPクライアントでのコンシューマーの実装は、他のスレッドまたはコード(発行を含む)のアクティビティとの競合を回避するために、1つの専用チャネルをコンシューマーに割り当てます。

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


1
「チャンネルをプールしないでください」、それが私が探しているものです
ospider

「それらは一時的であるため、チャネルはアプリによってプールされるべきではありません。」-どのようにしてこの結論に至ったのか説明してください。「スレッドごとに1つのチャネル」実装がリソースを使いすぎている場合、ドキュメントはチャネルプーリングを推奨しています。次を
ymas

@ymas-あなたが参照しているドキュメントは推測的なものであり、私の意見では、不十分なガイダンスです。ソースコードとプロトコル仕様を読んでいます。チャネルはプールされません、期間。さらに、スレッドごとに1つのチャネルは、これと同じ原理に基づくガイダンスです。オープンチャネルが多すぎてサーバーのリソースに制約があることがわかった場合は、アーキテクチャを再評価する(つまり、高可用性スキームに切り替えるか、同時実行性を減らす)必要があります。
theMayer

21

AMQPモデルのすべての側面を説明するこの記事を見つけました。チャネルはその1つです。理解を深めるのにとても役立ちました

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

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

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

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


4

TCP接続には複数のチャネルを設定できるなど関係があります。

チャネル:接続内の仮想接続です。キューからメッセージをパブリッシュまたはコンシュームする場合、すべてチャネルを介して行われます。一方、接続:アプリケーションとRabbitMQブローカー間のTCP接続です。

マルチスレッドアーキテクチャでは、スレッドごとに個別の接続が必要になる場合があります。これにより、TCP接続が十分に活用されない可能性があります。また、ネットワークのピーク時に必要な数のTCP接続を確立するために、オペレーティングシステムにオーバーヘッドが追加されます。システムのパフォーマンスが大幅に低下する可能性があります。これは、チャネルが便利になる場所であり、TCP接続内に仮想接続を作成します。OSのオーバーヘッドを削減するだけでなく、非同期操作をより高速で信頼性の高い方法で同時に実行することもできます。 ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.