RabbitMQ et relation entre le canal et la connexion

176

Le client Java RabbitMQ présente les concepts suivants:

  • Connection - une connexion à une instance de serveur RabbitMQ
  • Channel - ???
  • Pool de threads consommateurs - un pool de threads qui consomment les messages des files d'attente du serveur RabbitMQ
  • File d'attente - une structure qui contient les messages dans l'ordre FIFO

J'essaie de comprendre la relation et, plus important encore , les associations entre eux.

  1. Je ne suis toujours pas tout à fait sûr de ce qu'est a Channel, à part le fait qu'il s'agit de la structure à partir de laquelle vous publiez et utilisez, et qu'elle est créée à partir d'une connexion ouverte. Si quelqu'un pouvait m'expliquer ce que représente la "chaîne", cela pourrait aider à clarifier certaines choses.
  2. Quelle est la relation entre Channel et Queue? Le même canal peut-il être utilisé pour communiquer avec plusieurs files d'attente, ou doit-il être 1: 1?
  3. Quelle est la relation entre la file d'attente et le pool de consommateurs? Plusieurs consommateurs peuvent-ils être abonnés à la même file d'attente? Plusieurs files d'attente peuvent-elles être utilisées par le même consommateur? Ou la relation est-elle 1: 1?

Merci d'avance pour toute aide ici!


la source
Les réponses à cette question m'ont conduit à signaler ce problème avec le client golang plutôt que de poser la question ici.
Bruce Adams le
Le canal est un concept logique utilisé pour multiplexer une seule connexion TCP physique entre un client et un nœud. Le numéro de canal est inclus dans l'en-tête de message de la trame AMQP.
ymas le

Réponses:

196
  1. A Connectionreprésente une connexion TCP réelle au courtier de messages, tandis que a Channelest une connexion virtuelle (connexion AMQP) à l'intérieur. De cette façon, vous pouvez utiliser autant de connexions (virtuelles) que vous le souhaitez dans votre application sans surcharger le courtier avec des connexions TCP.

  2. Vous pouvez en utiliser un Channelpour tout. Cependant, si vous avez plusieurs threads, il est suggéré d'utiliser un autreChannel pour chaque thread.

    Channel thread-safety dans le guide de l'API du client Java :

    Les instances de canal peuvent être utilisées en toute sécurité par plusieurs threads. Les demandes dans un canal sont sérialisées, avec un seul thread pouvant exécuter une commande sur le canal à la fois. Même dans ce cas, les applications devraient préférer utiliser un canal par thread au lieu de partager le même canal sur plusieurs threads.

    Il n'y a pas de relation directe entre Channelet Queue. A Channelest utilisé pour envoyer des commandes AMQP au courtier. Cela peut être la création d'une file d'attente ou similaire, mais ces concepts ne sont pas liés.

  3. Chacun Consumers'exécute dans son propre thread alloué à partir du pool de threads consommateur. Si plusieurs consommateurs sont abonnés à la même file d'attente, le courtier utilise la répétition alternée pour distribuer les messages entre eux de manière égale. Voir le didacticiel 2: "Files d'attente de travail" .

    Il est également possible d'attacher le même Consumerà plusieurs files d'attente. Vous pouvez comprendre les consommateurs comme des rappels. Ceux-ci sont appelés chaque fois qu'un message arrive sur une file d'attente à laquelle le consommateur est lié. Dans le cas du client Java, chaque consommateur a une méthode handleDelivery(...), qui représente la méthode de rappel. En règle générale, vous sous DefaultConsumer-classez et remplacez handleDelivery(...). Remarque: Si vous attachez la même instance Consumer à plusieurs files d'attente, cette méthode sera appelée par différents threads. Veillez donc à la synchronisation si nécessaire.

Bengt
la source
4
Juste pour ajouter à partir de la documentation: les rappels aux consommateurs sont distribués sur un thread distinct du thread géré par la connexion. Cela signifie que les consommateurs peuvent appeler en toute sécurité des méthodes de blocage sur la connexion ou le canal, telles que queueDeclare, txCommit, basicCancel ou basicPublish. Chaque canal a son propre thread de distribution. Dans le cas d'utilisation le plus courant d'un consommateur par canal, cela signifie que les consommateurs ne retardent pas les autres consommateurs. Si vous avez plusieurs consommateurs par canal, sachez qu'un consommateur de longue date peut retarder l'envoi de rappels à d'autres consommateurs sur ce canal.
filip
1
Si vous attachez la même instance Consumer à plusieurs files d'attente du même canal, cela signifierait que les rappels sont distribués sur le même thread. Dans ce cas, vous n'auriez pas besoin de synchronisation, n'est-ce pas?
filip
Puis-je utiliser une seule connexion et utiliser un pool de canaux au lieu d'un pool de connexions? Cela affectera-t-il le débit de publication des messages?
qeek
4
Je pense que cette référence à l'API client Java est désormais obsolète et qu'en fait la référence d'aujourd'hui contredit directement la citation de cette réponse. La référence d'aujourd'hui indique que "les instances de canal ne doivent pas être partagées entre les threads".
Edwin Dalorzo
1
@EdwinDalorzo - il semble que celui qui a écrit la documentation à l'origine n'a pas entièrement compris la dichotomie entre les canaux et les connexions. L'architecture fondamentale d'AMQP 0.9.1 traite vraiment un canal comme une session, donc différents threads partageant une session sont vraiment absurdes. Je suppose que c'est la raison du changement.
theMayer
54

Une bonne compréhension conceptuelle de ce que fait le protocole AMQP «sous le capot» est utile ici. Je dirais que la documentation et l'API qu'AMQP 0.9.1 a choisi de déployer rendent cela particulièrement déroutant, donc la question elle-même est une question avec laquelle beaucoup de gens doivent se débattre.

TL; DR

Une connexion est le socket TCP physique négocié avec le serveur AMQP. Les clients correctement implémentés en auront un par application, thread-safe, partageable entre les threads.

Un canal est une session d'application unique sur la connexion. Un fil aura une ou plusieurs de ces sessions. L'architecture AMQP 0.9.1 est que ceux-ci ne doivent pas être partagés entre les threads, et doivent être fermés / détruits lorsque le thread qui l'a créé en a terminé. Ils sont également fermés par le serveur lorsque diverses violations de protocole se produisent.

Un consommateur est une construction virtuelle qui représente la présence d'une «boîte aux lettres» sur un canal particulier. L'utilisation d'un consommateur indique au courtier de pousser les messages d'une file d'attente particulière vers ce point de terminaison de canal.

Faits de connexion

Tout d'abord, comme d'autres l'ont souligné à juste titre, une connexion est l'objet qui représente la connexion TCP réelle au serveur. Les connexions sont spécifiées au niveau du protocole dans AMQP et toutes les communications avec le courtier se font via une ou plusieurs connexions.

  • Puisqu'il s'agit d'une connexion TCP réelle, elle a une adresse IP et un numéro de port.
  • Les paramètres de protocole sont négociés sur une base par client dans le cadre de la configuration de la connexion (un processus connu sous le nom de handshake .
  • Il est conçu pour durer longtemps ; il existe peu de cas où la fermeture de la connexion fait partie de la conception du protocole.
  • Du point de vue OSI, il réside probablement quelque part autour de la couche 6
  • Les pulsations peuvent être configurées pour surveiller l'état de la connexion, car TCP ne contient rien en lui-même pour ce faire.
  • Il est préférable qu'un thread dédié gère les lectures et les écritures sur le socket TCP sous-jacent. La plupart des clients RabbitMQ, sinon tous, le font. À cet égard, ils sont généralement thread-safe.
  • Relativement parlant, les connexions sont "chères" à créer (en raison de la poignée de main), mais en pratique, cela n'a pas vraiment d'importance. La plupart des processus n'auront vraiment besoin que d'un seul objet de connexion. Mais, vous pouvez maintenir les connexions dans un pool, si vous trouvez que vous avez besoin de plus de débit qu'un seul thread / socket ne peut en fournir (peu probable avec la technologie informatique actuelle).

Informations sur la chaîne

Un canal est la session d'application qui est ouverte pour chaque élément de votre application pour communiquer avec le courtier RabbitMQ. Il fonctionne sur une seule connexion et représente une session avec le courtier.

  • Comme il représente une partie logique de la logique d'application, chaque canal existe généralement sur son propre thread.
  • En règle générale, tous les canaux ouverts par votre application partageront une seule connexion (ce sont des sessions légères qui fonctionnent au-dessus de la connexion). Les connexions sont thread-safe, donc c'est OK.
  • La plupart des opérations AMQP ont lieu sur des canaux.
  • Du point de vue de la couche OSI, les canaux sont probablement autour de la couche 7 .
  • Les canaux sont conçus pour être transitoires ; Une partie de la conception d'AMQP est que le canal est généralement fermé en réponse à une erreur (par exemple, re-déclarer une file d'attente avec des paramètres différents avant de supprimer la file d'attente existante).
  • Comme ils sont transitoires, les canaux ne doivent pas être regroupés par votre application.
  • Le serveur utilise un entier pour identifier un canal. Lorsque le thread gérant la connexion reçoit un paquet pour un canal particulier, il utilise ce numéro pour indiquer au courtier à quel canal / session le paquet appartient.
  • Les canaux ne sont généralement pas sûrs pour les threads car il n'aurait aucun sens de les partager entre les threads. Si vous avez un autre thread qui doit utiliser le courtier, un nouveau canal est nécessaire.

Faits sur les consommateurs

Un consommateur est un objet défini par le protocole AMQP. Ce n'est ni un canal ni une connexion, mais plutôt quelque chose que votre application particulière utilise comme une sorte de «boîte aux lettres» pour déposer des messages.

  • "Créer un consommateur" signifie que vous dites au courtier (en utilisant un canal via une connexion ) que vous souhaitez que les messages vous soient envoyés via ce canal. En réponse, le courtier enregistrera que vous avez un consommateur sur le canal et commencera à vous envoyer des messages.
  • Chaque message poussé sur la connexion référencera à la fois un numéro de canal et un numéro de consommateur . De cette façon, le thread de gestion de connexion (dans ce cas, dans l'API Java) sait quoi faire avec le message; ensuite, le thread de gestion des canaux sait également quoi faire avec le message.
  • L'implémentation grand public présente la plus grande variation, car elle est littéralement spécifique à l'application. Dans ma mise en œuvre, j'ai choisi de spin off une tâche à chaque fois qu'un message arrivait via le consommateur; ainsi, j'avais un thread gérant la connexion, un thread gérant le canal (et par extension, le consommateur), et un ou plusieurs threads de tâches pour chaque message délivré via le consommateur.
  • La fermeture d'une connexion ferme tous les canaux de la connexion. La fermeture d'un canal ferme tous les consommateurs sur le canal. Il est également possible d' annuler un consommateur (sans fermer le canal). Il existe divers cas où il est logique de faire l'une des trois choses.
  • En règle générale, l'implémentation d'un consommateur dans un client AMQP allouera un canal dédié au consommateur pour éviter les conflits avec les activités d'autres threads ou code (y compris la publication).

En ce qui concerne ce que vous entendez par pool de threads grand public, je soupçonne que le client Java fait quelque chose de similaire à ce que j'ai programmé pour mon client (le mien était basé sur le client .Net, mais fortement modifié).

theMayer
la source
1
"les chaînes ne devraient pas être mises en commun", c'est ce que je recherche
ospider
"Comme ils sont transitoires, les chaînes ne doivent pas être mises en commun par votre application." - pouvez-vous clarifier comment vous êtes arrivé à cette conclusion s'il vous plaît. La documentation recommande le pool de canaux si l'implémentation "un canal par thread" utilise trop de ressources, voir ici: rabbitmq.com/channels.html#resource-usage
ymas
@ymas - La documentation à laquelle vous faites référence est spéculative et, à mon avis, une mauvaise orientation. Je lis le code source et les spécifications du protocole. Les canaux ne doivent pas être mis en commun, point final. De plus, un canal par fil est un guidage basé sur ce même principe. Si vous constatez que vous avez tellement de canaux ouverts que le serveur est limité en ressources, vous devez réévaluer votre architecture (c'est-à-dire passer à un schéma de haute disponibilité et / ou réduire la concurrence).
theMayer
21

J'ai trouvé cet article qui explique tous les aspects du modèle AMQP, dont le canal en fait partie. J'ai trouvé cela très utile pour compléter ma compréhension

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

Certaines applications nécessitent plusieurs connexions à un courtier AMQP. Cependant, il n'est pas souhaitable de garder de nombreuses connexions TCP ouvertes en même temps car cela consomme des ressources système et rend plus difficile la configuration des pare-feu. Les connexions AMQP 0-9-1 sont multiplexées avec des canaux qui peuvent être considérés comme des «connexions légères partageant une seule connexion TCP».

Pour les applications qui utilisent plusieurs threads / processus pour le traitement, il est très courant d'ouvrir un nouveau canal par thread / processus et de ne pas partager de canaux entre eux.

La communication sur un canal particulier est complètement séparée de la communication sur un autre canal, par conséquent, chaque méthode AMQP porte également un numéro de canal que les clients utilisent pour déterminer à quel canal la méthode est destinée (et donc, quel gestionnaire d'événements doit être appelé, par exemple) .

CamW
la source
4

Il existe une relation entre comme Une connexion TCP peut avoir plusieurs canaux .

Channel : C'est une connexion virtuelle à l'intérieur d'une connexion. Lors de la publication ou de la consommation de messages à partir d'une file d'attente, tout se fait sur un canal alors que la connexion : il s'agit d'une connexion TCP entre votre application et le courtier RabbitMQ.

Dans l'architecture multi-threading, vous pouvez avoir besoin d'une connexion distincte par thread. Cela peut conduire à une sous-utilisation de la connexion TCP, et cela ajoute également une surcharge au système d'exploitation pour établir autant de connexions TCP dont il a besoin pendant la période de pointe du réseau. Les performances du système pourraient être considérablement réduites. C'est là que le canal est utile, il crée des connexions virtuelles à l'intérieur d'une connexion TCP. Cela réduit d'emblée la surcharge du système d'exploitation, et nous permet également d'effectuer des opérations asynchrones de manière plus rapide, fiable et simultanée. entrez la description de l'image ici

Atul Jain
la source