RabbitMQ und Beziehung zwischen Kanal und Verbindung


176

Der RabbitMQ Java-Client verfügt über die folgenden Konzepte:

  • Connection - eine Verbindung zu einer RabbitMQ-Serverinstanz
  • Channel - ???
  • Consumer-Thread-Pool - Ein Pool von Threads, die Nachrichten aus den RabbitMQ-Serverwarteschlangen verbrauchen
  • Warteschlange - eine Struktur, die Nachrichten in FIFO-Reihenfolge enthält

Ich versuche die Beziehung und vor allem die Assoziationen zwischen ihnen zu verstehen .

  1. Ich bin mir immer noch nicht ganz sicher, was ein Channelist, abgesehen von der Tatsache, dass dies die Struktur ist, aus der Sie veröffentlichen und konsumieren, und dass sie aus einer offenen Verbindung erstellt wird. Wenn mir jemand erklären könnte, was der "Kanal" darstellt, könnte dies helfen, ein paar Dinge zu klären.
  2. Wie ist die Beziehung zwischen Kanal und Warteschlange? Kann derselbe Kanal für die Kommunikation mit mehreren Warteschlangen verwendet werden oder muss er 1: 1 sein?
  3. Welche Beziehung besteht zwischen der Warteschlange und dem Verbraucherpool? Können mehrere Verbraucher dieselbe Warteschlange abonnieren? Können mehrere Warteschlangen von demselben Verbraucher verwendet werden? Oder ist die Beziehung 1: 1?

Vielen Dank im Voraus für jede Hilfe hier!


Die Antworten auf diese Frage führten dazu, dass ich dieses Problem beim Golang-Kunden meldete, anstatt die Frage hier zu stellen.
Bruce Adams

Der Kanal ist ein logisches Konzept, das zum Multiplexen einer einzelnen physischen TCP-Verbindung zwischen einem Client und einem Knoten verwendet wird. Die Kanalnummer ist im Nachrichtenkopf des AMQP-Frames enthalten.
Weihnachten

Antworten:


196
  1. A Connectionstellt eine echte TCP-Verbindung zum Nachrichtenbroker dar, während a Channeleine virtuelle Verbindung (AMQP-Verbindung) darin ist. Auf diese Weise können Sie in Ihrer Anwendung so viele (virtuelle) Verbindungen verwenden, wie Sie möchten, ohne den Broker mit TCP-Verbindungen zu überlasten.

  2. Sie können eine Channelfür alles verwenden. Wenn Sie jedoch mehrere Threads haben, wird empfohlen, einen anderen zu verwendenChannel für jeden Thread zu verwenden.

    Sicherheit von Kanalthreads im Java Client API-Handbuch :

    Kanalinstanzen können sicher von mehreren Threads verwendet werden. Anforderungen an einen Kanal werden serialisiert, wobei jeweils nur ein Thread einen Befehl auf dem Kanal ausführen kann. Trotzdem sollten Anwendungen es vorziehen, einen Kanal pro Thread zu verwenden, anstatt denselben Kanal über mehrere Threads hinweg zu teilen.

    Es gibt keine direkte Beziehung zwischen ChannelundQueue . A Channelwird verwendet, um AMQP-Befehle an den Broker zu senden. Dies kann die Erstellung einer Warteschlange oder ähnlichem sein, aber diese Konzepte sind nicht miteinander verbunden.

  3. Jeder Consumer in einem eigenen Thread ausgeführt, der aus dem Consumer-Thread-Pool zugewiesen wird. Wenn mehrere Verbraucher dieselbe Warteschlange abonniert haben, verwendet der Broker Round-Robin, um die Nachrichten gleichmäßig zwischen ihnen zu verteilen. Siehe Tutorial 2: "Arbeitswarteschlangen" .

    Es ist auch möglich, dasselbe Consumeran mehrere Warteschlangen anzuhängen . Sie können Verbraucher als Rückrufe verstehen. Diese werden jedes Mal aufgerufen, wenn eine Nachricht in einer Warteschlange eintrifft, an die der Verbraucher gebunden ist. Für den Fall des Java-Clients verfügt jeder Verbraucher über eine Methode handleDelivery(...), die die Rückrufmethode darstellt. Was Sie normalerweise tun, ist Unterklasse DefaultConsumerund Überschreiben handleDelivery(...). Hinweis: Wenn Sie dieselbe Consumer-Instanz an mehrere Warteschlangen anhängen, wird diese Methode von verschiedenen Threads aufgerufen. Achten Sie also bei Bedarf auf die Synchronisation.


4
Nur um aus der Dokumentation hinzuzufügen: Rückrufe an Verbraucher werden auf einem Thread gesendet, der von dem von der Verbindung verwalteten Thread getrennt ist. Dies bedeutet, dass Verbraucher Blockierungsmethoden für die Verbindung oder den Kanal sicher aufrufen können, z. B. queueDeclare, txCommit, basicCancel oder basicPublish. Jeder Kanal hat einen eigenen Versand-Thread. Für den häufigsten Anwendungsfall eines Verbrauchers pro Kanal bedeutet dies, dass Verbraucher andere Verbraucher nicht aufhalten. Wenn Sie mehrere Verbraucher pro Kanal haben, beachten Sie, dass ein langjähriger Verbraucher möglicherweise den Rückruf von Rückrufen an andere Verbraucher auf diesem Kanal verzögert.
Filip

1
Wenn Sie dieselbe Consumer-Instanz an mehrere Warteschlangen desselben Kanals anhängen, bedeutet dies, dass die Rückrufe auf demselben Thread gesendet werden. In diesem Fall würden Sie keine Synchronisation benötigen, oder?
Filip

Kann ich nur eine Verbindung verwenden und einen Kanalpool anstelle eines Verbindungspools verwenden? Wird dies den Durchsatz der Nachrichtenveröffentlichung beeinflussen?
Qeek

4
Ich denke, dieser Verweis auf die Java Client API ist mittlerweile veraltet und der heutige Verweis widerspricht direkt dem Zitat in dieser Antwort. Die heutige Referenz besagt, dass "Kanalinstanzen nicht zwischen Threads geteilt werden dürfen".
Edwin Dalorzo

1
@EdwinDalorzo - es sieht so aus, als hätte derjenige, der ursprünglich die Dokumentation geschrieben hat, die Dichotomie der Kanalverbindung nicht vollständig verstanden. Die grundlegende Architektur von AMQP 0.9.1 behandelt einen Kanal wirklich als Sitzung, sodass verschiedene Threads, die eine Sitzung gemeinsam nutzen, wirklich Unsinn sind. Ich vermute, das ist der Grund für die Änderung.
theMayer

53

Hier ist ein gutes konzeptionelles Verständnis der Funktionsweise des AMQP-Protokolls "unter der Haube" hilfreich. Ich würde anbieten, dass die Dokumentation und API, die AMQP 0.9.1 für die Bereitstellung ausgewählt hat, dies besonders verwirrend macht, sodass die Frage selbst eine ist, mit der sich viele Menschen auseinandersetzen müssen.

TL; DR

Eine Verbindung ist der physisch ausgehandelte TCP-Socket mit dem AMQP-Server. Bei ordnungsgemäß implementierten Clients ist eine dieser Anwendungen pro Anwendung threadsicher und kann unter Threads gemeinsam genutzt werden.

Ein Kanal ist eine einzelne Anwendungssitzung für die Verbindung. Ein Thread hat eine oder mehrere dieser Sitzungen. Die AMQP-Architektur 0.9.1 sieht vor, dass diese nicht von Threads gemeinsam genutzt werden dürfen und geschlossen / zerstört werden sollten, wenn der Thread, der sie erstellt hat, damit fertig ist. Sie werden auch vom Server geschlossen, wenn verschiedene Protokollverletzungen auftreten.

Ein Consumer ist ein virtuelles Konstrukt, das das Vorhandensein einer "Mailbox" auf einem bestimmten Kanal darstellt. Die Verwendung eines Verbrauchers weist den Broker an, Nachrichten von einer bestimmten Warteschlange an diesen Kanalendpunkt zu senden.

Verbindungsdaten

Erstens, wie andere richtig betont haben, a Verbindung das Objekt, das die tatsächliche TCP-Verbindung zum Server darstellt. Verbindungen werden in AMQP auf Protokollebene angegeben, und die gesamte Kommunikation mit dem Broker erfolgt über eine oder mehrere Verbindungen.

  • Da es sich um eine tatsächliche TCP-Verbindung handelt, verfügt sie über eine IP-Adresse und eine Portnummer.
  • Protokollparameter werden im Rahmen des Verbindungsaufbaus pro Client ausgehandelt (ein Prozess, der als Handshake bezeichnet wird) .
  • Es ist so konzipiert, dass es langlebig ist ; Es gibt nur wenige Fälle, in denen das Schließen der Verbindung Teil des Protokolldesigns ist.
  • Aus OSI-Sicht befindet es sich wahrscheinlich irgendwo in der Nähe von Schicht 6
  • Heartbeats können eingerichtet werden, um den Verbindungsstatus zu überwachen, da TCP an und für sich nichts enthält, um dies zu tun.
  • Es ist am besten, wenn ein dedizierter Thread Lese- und Schreibvorgänge auf dem zugrunde liegenden TCP-Socket verwaltet. Die meisten, wenn nicht alle RabbitMQ-Clients tun dies. In dieser Hinsicht sind sie im Allgemeinen threadsicher.
  • Relativ gesehen sind Verbindungen "teuer" (aufgrund des Handshakes), aber praktisch spielt dies keine Rolle. Die meisten Prozesse benötigen wirklich nur ein Verbindungsobjekt. Sie können jedoch Verbindungen in einem Pool aufrechterhalten, wenn Sie feststellen, dass Sie mehr Durchsatz benötigen, als ein einzelner Thread / Socket bereitstellen kann (mit der aktuellen Computertechnologie unwahrscheinlich).

Kanal Fakten

Ein Kanal ist die Anwendungssitzung, die für jeden Teil Ihrer App geöffnet wird, um mit dem RabbitMQ-Broker zu kommunizieren. Es arbeitet über eine einzelne Verbindung und repräsentiert eine Sitzung mit dem Broker.

  • Da es einen logischen Teil der Anwendungslogik darstellt, existiert normalerweise jeder Kanal in einem eigenen Thread.
  • In der Regel teilen sich alle von Ihrer App geöffneten Kanäle eine einzige Verbindung (dies sind einfache Sitzungen, die über der Verbindung ausgeführt werden). Die Verbindungen sind threadsicher, daher ist dies in Ordnung.
  • Die meisten AMQP-Operationen finden über Kanäle statt.
  • Aus Sicht der OSI-Schicht befinden sich die Kanäle wahrscheinlich in der Nähe von Schicht 7 .
  • Kanäle sind so konzipiert, dass sie vorübergehend sind . Teil des Entwurfs von AMQP ist, dass der Kanal normalerweise als Reaktion auf einen Fehler geschlossen wird (z. B. erneutes Deklarieren einer Warteschlange mit verschiedenen Parametern vor dem Löschen der vorhandenen Warteschlange).
  • Da sie vorübergehend sind, sollten Kanäle nicht von Ihrer App gepoolt werden.
  • Der Server verwendet eine Ganzzahl, um einen Kanal zu identifizieren. Wenn der Thread, der die Verbindung verwaltet, ein Paket für einen bestimmten Kanal empfängt, verwendet er diese Nummer, um dem Broker mitzuteilen, zu welchem ​​Kanal / welcher Sitzung das Paket gehört.
  • Kanäle sind im Allgemeinen nicht threadsicher, da es keinen Sinn macht, sie zwischen Threads zu teilen. Wenn Sie einen anderen Thread haben, der den Broker verwenden muss, wird ein neuer Kanal benötigt.

Verbraucher Fakten

Ein Verbraucher ist ein Objekt, das durch das AMQP-Protokoll definiert ist. Es ist weder ein Kanal noch eine Verbindung, sondern etwas, das Ihre spezielle Anwendung als eine Art "Postfach" zum Löschen von Nachrichten verwendet.

  • "Erstellen eines Verbrauchers" bedeutet, dass Sie dem Broker (über einen Kanal über eine Verbindung ) mitteilen, dass Sie Nachrichten über diesen Kanal an Sie senden möchten. Als Antwort registriert der Broker, dass Sie einen Verbraucher im Kanal haben, und beginnt, Nachrichten an Sie zu senden.
  • Jede über die Verbindung übertragene Nachricht verweist sowohl auf eine Kanalnummer als auch auf eine Verbrauchernummer . Auf diese Weise weiß der verbindungsverwaltende Thread (in diesem Fall innerhalb der Java-API), was mit der Nachricht zu tun ist. Dann weiß der Channel-Handling-Thread auch, was mit der Nachricht zu tun ist.
  • Die Implementierung von Verbrauchern ist am unterschiedlichsten, da sie buchstäblich anwendungsspezifisch ist. In meiner Implementierung habe ich mich entschieden, jedes Mal eine Aufgabe auszulagern, wenn eine Nachricht über den Verbraucher eingeht. Daher hatte ich einen Thread, der die Verbindung verwaltete, einen Thread, der den Kanal (und damit auch den Verbraucher) verwaltete, und einen oder mehrere Task-Threads für jede über den Verbraucher übermittelte Nachricht.
  • Durch das Schließen einer Verbindung werden alle Kanäle der Verbindung geschlossen. Durch das Schließen eines Kanals werden alle Verbraucher auf dem Kanal geschlossen. Es ist auch möglich, einen Verbraucher abzubrechen (ohne den Kanal zu schließen). Es gibt verschiedene Fälle, in denen es sinnvoll ist, eines der drei Dinge zu tun.
  • In der Regel weist die Implementierung eines Verbrauchers in einem AMQP-Client dem Verbraucher einen dedizierten Kanal zu, um Konflikte mit den Aktivitäten anderer Threads oder Codes (einschließlich Veröffentlichung) zu vermeiden.

In Bezug auf das, was Sie unter Consumer-Thread-Pool verstehen, vermute ich, dass der Java-Client etwas Ähnliches tut, wie ich meinen Client programmiert habe (meiner basierte auf dem .Net-Client, wurde jedoch stark modifiziert).


1
"Kanäle sollten nicht gepoolt werden", das ist es, wonach ich suche
ospider

"Da sie vorübergehend sind, sollten Kanäle nicht von Ihrer App gepoolt werden." - Können Sie bitte klären, wie Sie zu diesem Schluss gekommen sind? In den Dokumenten wird das Channel-Pooling empfohlen, wenn die Implementierung "Ein Kanal pro Thread" zu viele Ressourcen verwendet. Weitere
Informationen finden

@ymas - Die Dokumentation, auf die Sie sich beziehen, ist spekulativ und meiner Meinung nach eine schlechte Anleitung. Ich lese den Quellcode und die Protokollspezifikation. Kanäle sind nicht zu bündeln, Punkt. Ferner ist ein Kanal pro Thread eine Führung, die auf demselben Prinzip basiert. Wenn Sie feststellen, dass Sie so viele offene Kanäle haben, dass der Server ressourcenbeschränkt ist, müssen Sie Ihre Architektur neu bewerten (dh zu einem Hochverfügbarkeitsschema wechseln und / oder die Parallelität verringern).
theMayer

21

Ich habe diesen Artikel gefunden, der alle Aspekte des AMQP-Modells erklärt, von denen Channel einer ist. Ich fand es sehr hilfreich, um mein Verständnis abzurunden

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

Einige Anwendungen benötigen mehrere Verbindungen zu einem AMQP-Broker. Es ist jedoch unerwünscht, viele TCP-Verbindungen gleichzeitig offen zu halten, da dies Systemressourcen verbraucht und die Konfiguration von Firewalls erschwert. AMQP 0-9-1-Verbindungen werden mit Kanälen gemultiplext, die als "einfache Verbindungen, die sich eine einzelne TCP-Verbindung teilen" angesehen werden können.

Bei Anwendungen, die mehrere Threads / Prozesse für die Verarbeitung verwenden, ist es sehr üblich, einen neuen Kanal pro Thread / Prozess zu öffnen und keine Kanäle zwischen ihnen zu teilen.

Die Kommunikation auf einem bestimmten Kanal ist vollständig von der Kommunikation auf einem anderen Kanal getrennt. Daher enthält jede AMQP-Methode auch eine Kanalnummer, mit der Clients herausfinden, für welchen Kanal die Methode bestimmt ist (und somit beispielsweise, welcher Ereignishandler aufgerufen werden muss). .


4

Es gibt eine Beziehung zwischen wie Eine TCP-Verbindung kann mehrere Kanäle haben .

Kanal : Es ist eine virtuelle Verbindung innerhalb einer Verbindung. Beim Veröffentlichen oder Konsumieren von Nachrichten aus einer Warteschlange erfolgt alles über einen Kanal. Verbindung : Es handelt sich um eine TCP-Verbindung zwischen Ihrer Anwendung und dem RabbitMQ-Broker.

In einer Multithreading-Architektur benötigen Sie möglicherweise eine separate Verbindung pro Thread. Dies kann zu einer unzureichenden Auslastung der TCP-Verbindung führen. Außerdem erhöht dies den Aufwand für das Betriebssystem, um so viele TCP-Verbindungen herzustellen, wie während der Spitzenzeit des Netzwerks erforderlich sind. Die Leistung des Systems könnte drastisch reduziert werden. Hier bietet sich der Kanal an, der virtuelle Verbindungen innerhalb einer TCP-Verbindung herstellt. Dies reduziert sofort den Overhead des Betriebssystems und ermöglicht es uns, asynchrone Vorgänge schneller, zuverlässiger und gleichzeitig auszuführen. Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.