RabbitMQ, comment court le lapin agile

Le modèle que définit le protocole AMQP est très simple : des « brokers » reçoivent des messages de « publishers » (ou « producers ») et les routent vers des « consumers ». Les publishers, brokers et consumers sont généralement sur différentes machines, et communiquent à travers un réseau.

Dès que l’on commence à manipuler RabbitMQ, les choses se compliquent un peu. J’espère que ces notes vous permettront de gagner du temps pour comprendre les détails de son fonctionnement.

Un « broker » (serveur) RabbitMQ possède les éléments suivants :

  • des « virtual hosts » (vhosts) qui constituent des environnements isolés les uns des autres.
  • des « users », identifiés par un login et mot de passe ou un certificat SSL, à qui on donne accès à certains « virtual hosts ».
  • des « exchanges », définies au sein d’un « virtual host », qui possèdent chacun un type et quelques autres paramètres dont une « durability » (indique si il survit à un restart du serveur) et un « auto-delete » (il est supprimé si aucune queue n’est plus associée).
  • des « queues », définies également au sein d’un « virtual host », qui reçoivent et bufferisent les messages distribués par leur « exchange ».
  • des « bindings », associations entre une « queue » et un « exchange ». On peut dire qu’un « binding » exprime l’intérêt d’une « queue » pour les messages qui transitent via un « exchange ».

Le « producer » se connecte à un vhost avec ses « credentials » (login et mdp). Il envoie un message non pas vers une queue, mais plutôt vers un « exchange », avec comme paramètre une « routing_key ».

Une « routing_key » prend différentes formes : elle peut être vide (dans le cas d’un envoi vers un exchange de type fanout ; fanout veut dire distribuer, « ouvrir en éventail », et indique une distribution à toutes les queues de tous les messages) ; elle peut contenir le nom de la queue cible (dans le cas d’un envoi vers l’exchange non-nommé  ») ; elle peut contenir un mot (exchange de type direct) ou un ensemble de mots séparés par des points (exchange de type topic).

Un « exchange » reçoit donc un message d’un « producer » et le route vers zéro, une ou plusieurs « queues ». L’algorithme de routage dépend du type d’exchange (direct, topic, headers, fanout), des « bindings » associés à l’exchange et de la routing_key associée au message.

C’est le « consumer » qui crée un « binding », par exemple pour récupérer dans une queue juste créée tous les messages d’un exchange de type fanout. Un binding peut définir un paramètre nommé « routing_key » (à ne pas confondre avec le paramètre d’envoi de message), que nous désignerons plutôt par « binding key ». Dans le cas d’un exchange de type direct, le routing_key du message et le binding key du binding doivent tout simplement être égaux pour que le message soit placé dans la queue. Dans le cas d’un exchange de type topic, l’un des mots du routing_key du message (ex orange.rabbit.runs) doit matcher la binding key, qui elle peuvent contenir des jockers (* et #).

Le « broker » délivre alors les messages au « consumers » abonnés au « queues » (push), ou bien les « consumers » récupèrent les messages dans la « queue » (pull).

Les réseaux ne sont pas fiables à 100%. Suivant les paramètres d’envoi du message, le broker supprime donc un message de la queue soit dès qu’il est délivré, soit quand le consumer a envoyé un « acknowledgment » du traitement du message.

Quand un serveur RabbitMQ démarre et détecte que sa base de données n’existe pas ou a été supprimée, il initialise une base de données vide, un virtual host nommé ‘/’ et un utilisateur ‘guest’ avec un mot de passe ‘guest’, qui a accès au vhost ‘/’. Ce vhost contient d’office plusieurs exchanges, dont l’un n’est pas nommé (désigné par  », de type direct) et les autres sont nommés amq.*, * étant un type d’exchange tel que ‘direct’.

A noter : l’exchange non-nommé à une propriété spécifique : toute queue créée dans le vhost lui est automatiquement associée avec une binding key égale au nom de la queue.

Dès que l’on crée un programme AMQP ou que l’on ouvre l’interface d’administration de RabbitMQ, deux autres concepts sont à prendre en compte :

Les « connections » sont les connexions TCP ouvertes par les producers et consumers pour communiquer avec le serveur. Ce sont de connexions longues, qui ne sont coupées que quand le noeud se détache du serveur.

Les « channels » sont des liens logiques qui partagent une même connexion TCP, et permettent ainsi à différents processus ou threads d’un même machine de communiquer avec le serveur RabbitMQ sans multiplier les ressources réseau entre deux machines.

Ces notions sont par exemple utilisées en Python quand le producer ou le consumer initie une connexion :

connection = pika.BlockingConnection(parameters)
channel = connection.channel()

C’est via la channel que s’effectuent ensuite les interactions avec le serveur :

channel.queue_declare(queue='hello')
channel.basic_publish( exchange='',
routing_key='hello',
body=message)

Et c’est la connexion qui est coupée en fin de processus :

connection.close()

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

WordPress Anti Spam par WP-SpamShield