{"id":54,"date":"2015-02-14T19:12:08","date_gmt":"2015-02-14T18:12:08","guid":{"rendered":"http:\/\/www.fluxnumerique.fr\/?p=54"},"modified":"2020-12-13T10:12:43","modified_gmt":"2020-12-13T09:12:43","slug":"rabbitmq-le-modele","status":"publish","type":"post","link":"https:\/\/www.fluxnumerique.fr\/?p=54","title":{"rendered":"RabbitMQ,  comment court le lapin agile"},"content":{"rendered":"<p>Le mod\u00e8le que d\u00e9finit le protocole AMQP est tr\u00e8s simple : des \u00ab\u00a0brokers\u00a0\u00bb re\u00e7oivent des messages de \u00ab\u00a0publishers\u00a0\u00bb (ou \u00ab\u00a0producers\u00a0\u00bb) et les routent vers des \u00ab\u00a0consumers\u00a0\u00bb. Les publishers, brokers et consumers sont g\u00e9n\u00e9ralement sur diff\u00e9rentes machines, et communiquent \u00e0 travers un r\u00e9seau.<\/p>\n<p>D\u00e8s que l&rsquo;on commence \u00e0 manipuler RabbitMQ, les choses se compliquent un peu. J&rsquo;esp\u00e8re que ces notes vous permettront de gagner du temps pour comprendre les d\u00e9tails de son fonctionnement.<\/p>\n<p>Un \u00ab\u00a0broker\u00a0\u00bb (serveur) RabbitMQ poss\u00e8de les \u00e9l\u00e9ments suivants :<\/p>\n<ul>\n<li>des \u00ab\u00a0virtual hosts\u00a0\u00bb (vhosts) qui constituent des environnements isol\u00e9s les uns des autres.<\/li>\n<li>des \u00ab\u00a0users\u00a0\u00bb, identifi\u00e9s par un login et mot de passe ou un certificat SSL, \u00e0 qui on donne acc\u00e8s \u00e0 certains \u00ab\u00a0virtual hosts\u00a0\u00bb.<\/li>\n<li>des \u00ab\u00a0exchanges\u00a0\u00bb, d\u00e9finies au sein d&rsquo;un \u00ab\u00a0virtual host\u00a0\u00bb, qui poss\u00e8dent chacun un type et quelques autres param\u00e8tres dont une \u00ab\u00a0durability\u00a0\u00bb (indique si il survit \u00e0 un restart du serveur) et un \u00ab\u00a0auto-delete\u00a0\u00bb (il est supprim\u00e9 si aucune queue n&rsquo;est plus associ\u00e9e).<\/li>\n<li>des \u00ab\u00a0queues\u00a0\u00bb, d\u00e9finies \u00e9galement au sein d&rsquo;un \u00ab\u00a0virtual host\u00a0\u00bb, qui re\u00e7oivent et bufferisent les messages distribu\u00e9s par leur \u00ab\u00a0exchange\u00a0\u00bb.<\/li>\n<li>des \u00ab\u00a0bindings\u00a0\u00bb, associations entre une \u00ab\u00a0queue\u00a0\u00bb et un \u00ab\u00a0exchange\u00a0\u00bb. On peut dire qu&rsquo;un \u00ab\u00a0binding\u00a0\u00bb exprime l&rsquo;int\u00e9r\u00eat d&rsquo;une \u00ab\u00a0queue\u00a0\u00bb pour les messages qui transitent via un \u00ab\u00a0exchange\u00a0\u00bb.<\/li>\n<\/ul>\n<p>Le \u00ab\u00a0producer\u00a0\u00bb se connecte \u00e0 un vhost avec ses \u00ab\u00a0credentials\u00a0\u00bb (login et mdp). Il envoie un message non pas vers une queue, mais plut\u00f4t vers un \u00ab\u00a0exchange\u00a0\u00bb, avec comme param\u00e8tre une \u00ab\u00a0routing_key\u00a0\u00bb.<\/p>\n<p>Une \u00ab\u00a0routing_key\u00a0\u00bb prend diff\u00e9rentes formes : elle peut \u00eatre vide (dans le cas d&rsquo;un envoi vers un exchange de type fanout ; fanout veut dire distribuer, \u00ab\u00a0ouvrir en \u00e9ventail\u00a0\u00bb, et indique une distribution \u00e0 toutes les queues de tous les messages) ; elle peut contenir le nom de la queue cible (dans le cas d&rsquo;un envoi vers l&rsquo;exchange non-nomm\u00e9 \u00a0\u00bb) ; elle peut contenir un mot (exchange de type direct) ou un ensemble de mots s\u00e9par\u00e9s par des points (exchange de type topic).<\/p>\n<p>Un \u00ab\u00a0exchange\u00a0\u00bb re\u00e7oit donc un message d&rsquo;un \u00ab\u00a0producer\u00a0\u00bb et le route vers z\u00e9ro, une ou plusieurs \u00ab\u00a0queues\u00a0\u00bb. L&rsquo;algorithme de routage d\u00e9pend du type d&rsquo;exchange (direct, topic, headers, fanout), des \u00ab\u00a0bindings\u00a0\u00bb associ\u00e9s \u00e0 l&rsquo;exchange et de la routing_key associ\u00e9e au message.<\/p>\n<p>C&rsquo;est le \u00ab\u00a0consumer\u00a0\u00bb qui cr\u00e9e un \u00ab\u00a0binding\u00a0\u00bb, par exemple pour r\u00e9cup\u00e9rer dans une queue juste cr\u00e9\u00e9e tous les messages d&rsquo;un exchange de type fanout. Un binding peut d\u00e9finir un param\u00e8tre nomm\u00e9 \u00ab\u00a0routing_key\u00a0\u00bb (\u00e0 ne pas confondre avec le param\u00e8tre d&rsquo;envoi de message), que nous d\u00e9signerons plut\u00f4t par \u00ab\u00a0binding key\u00a0\u00bb. Dans le cas d&rsquo;un exchange de type direct, le routing_key du message et le binding key du binding doivent tout simplement \u00eatre \u00e9gaux pour que le message soit plac\u00e9 dans la queue. Dans le cas d&rsquo;un exchange de type topic, l&rsquo;un des mots du routing_key du message (ex orange.rabbit.runs) doit matcher la binding key, qui elle peuvent contenir des jockers (* et #).<\/p>\n<p>Le \u00ab\u00a0broker\u00a0\u00bb d\u00e9livre alors les messages au \u00ab\u00a0consumers\u00a0\u00bb abonn\u00e9s au \u00ab\u00a0queues\u00a0\u00bb (push), ou bien les \u00ab\u00a0consumers\u00a0\u00bb r\u00e9cup\u00e8rent les messages dans la \u00ab\u00a0queue\u00a0\u00bb (pull).<\/p>\n<p>Les r\u00e9seaux ne sont pas fiables \u00e0 100%. Suivant les param\u00e8tres d&rsquo;envoi du message, le broker supprime donc un message de la queue soit d\u00e8s qu&rsquo;il est d\u00e9livr\u00e9, soit quand le consumer a envoy\u00e9 un \u00ab\u00a0acknowledgment\u00a0\u00bb du traitement du message.<\/p>\n<p>Quand un serveur RabbitMQ d\u00e9marre et d\u00e9tecte que sa base de donn\u00e9es n&rsquo;existe pas ou a \u00e9t\u00e9 supprim\u00e9e, il initialise une base de donn\u00e9es vide, un virtual host nomm\u00e9 &lsquo;\/&rsquo; et un utilisateur &lsquo;guest&rsquo; avec un mot de passe &lsquo;guest&rsquo;, qui a acc\u00e8s au vhost &lsquo;\/&rsquo;. Ce vhost contient d&rsquo;office plusieurs exchanges, dont l&rsquo;un n&rsquo;est pas nomm\u00e9 (d\u00e9sign\u00e9 par \u00a0\u00bb, de type direct) et les autres sont nomm\u00e9s amq.*, * \u00e9tant un type d&rsquo;exchange tel que &lsquo;direct&rsquo;.<\/p>\n<p>A noter : l&rsquo;exchange non-nomm\u00e9 \u00e0 une propri\u00e9t\u00e9 sp\u00e9cifique : toute queue cr\u00e9\u00e9e dans le vhost lui est automatiquement associ\u00e9e avec une binding key \u00e9gale au nom de la queue.<\/p>\n<p>D\u00e8s que l&rsquo;on cr\u00e9e un programme AMQP ou que l&rsquo;on ouvre l&rsquo;interface d&rsquo;administration de RabbitMQ, deux autres concepts sont \u00e0 prendre en compte :<\/p>\n<p>Les \u00ab\u00a0connections\u00a0\u00bb sont les connexions TCP ouvertes par les producers et consumers pour communiquer avec le serveur. Ce sont de connexions longues, qui ne sont coup\u00e9es que quand le noeud se d\u00e9tache du serveur.<\/p>\n<p>Les \u00ab\u00a0channels\u00a0\u00bb sont des liens logiques qui partagent une m\u00eame connexion TCP, et permettent ainsi \u00e0 diff\u00e9rents processus ou threads d&rsquo;un m\u00eame machine de communiquer avec le serveur RabbitMQ sans multiplier les ressources r\u00e9seau entre deux machines.<\/p>\n<p>Ces notions sont par exemple utilis\u00e9es en Python quand le producer ou le consumer initie une connexion :<\/p>\n<p><code>connection = pika.BlockingConnection(parameters)<br \/>\nchannel = connection.channel()<\/code><\/p>\n<p>C&rsquo;est via la channel que s&rsquo;effectuent ensuite les interactions avec le serveur :<\/p>\n<p><code>channel.queue_declare(queue='hello')<br \/>\nchannel.basic_publish( exchange='',<br \/>\nrouting_key='hello',<br \/>\nbody=message)<\/code><\/p>\n<p>Et c&rsquo;est la connexion qui est coup\u00e9e en fin de processus :<\/p>\n<p><code>connection.close()<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Le mod\u00e8le que d\u00e9finit le protocole AMQP est tr\u00e8s simple : des \u00ab\u00a0brokers\u00a0\u00bb re\u00e7oivent des messages de \u00ab\u00a0publishers\u00a0\u00bb (ou \u00ab\u00a0producers\u00a0\u00bb) et les routent vers des \u00ab\u00a0consumers\u00a0\u00bb. Les publishers, brokers et consumers sont g\u00e9n\u00e9ralement sur diff\u00e9rentes machines, et communiquent \u00e0 travers un r\u00e9seau. D\u00e8s que l&rsquo;on commence \u00e0 manipuler RabbitMQ, les choses se compliquent un peu.&hellip;<\/p>\n","protected":false},"author":1,"featured_media":58,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-54","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web"],"_links":{"self":[{"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/posts\/54","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=54"}],"version-history":[{"count":4,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/posts\/54\/revisions"}],"predecessor-version":[{"id":60,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/posts\/54\/revisions\/60"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=\/wp\/v2\/media\/58"}],"wp:attachment":[{"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=54"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=54"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fluxnumerique.fr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=54"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}