rabbitmq - nathcouret/SDTD-Mazerunner GitHub Wiki
RabbitMQ
Présentation générale
RabbitMQ est un middleware de Pivotal facilitant l’échange de messages entre applications présentes sur un système informatique : message broker software. RabbitMQ implémente le protocole AMQP (conçu par un consortium international) qui standardise les échanges de messages. Écrit en Erlang, RabbitMQ est open-source et un support payant est disponible. Des librairies sont disponibles pour l’écrasante majorité des langages utilisés, est compatible avec les principaux systèmes d’exploitation et bénéficie d’une large communauté d’utilisateurs. Il est utilisé par de nombreuses entreprises pour répondre à leurs besoins en échange de messages, telles que Instagram, The New York Times, Nokia, SoundCloud...
Fonctionnalitées
RabbitMQ propose les fonctionnalités suivantes :
- Le transport de messages ;
- La communication asynchrone : L’émetteur d'un message et le récepteur du message n'ont pas besoin d'être activés en même temps. La file d’attente reçoit le message de l'application émettrice et le stocke jusqu'à ce que l'application réceptrice vienne lire le message ;
- Le routage : Les messages peuvent être routés entre machines ;
- Le clustering : Plusieurs serveurs RabbitMQ peuvent former un cluster ;
- La persistance des messages : Les messages d’une file peuvent être sauvegardé sur un support physique ;
- La fiabilité : Chaque envoi ou réception par une application fait l'objet d'un accusé de réception. Couplé avec la persistance, ce mécanisme permet de garantir qu'aucun message ne sera perdu dans son transfert entre les applications ;
- La diversité des protocoles supportés : AMQP, STOMP, MQTT, AMQP, HTTP ;
- La diversité des clients : Java, Python, .NET, Ruby, PHP, etc… (plus de 20).
Principes de fonctionnement
RabbitMQ propose les différents cas d'utilisation :
- Point à point : Une seule application productrice et une seule consommatrice. Le message est retiré de la file d’attente lorsque le consommateur l’a lu ;
- Publish-subscribe : Les applications consommatrices des messages s'abonnent à un channel correspondant à une catégorie de messages qu’elles veulent recevoir. Tous les messages du channel restent disponibles tant que tous les abonnés ne les ont pas lu ;
- Work queue : Une application remplit une file de job à exécuter. Des serveurs viennent récupérer ces tâches pour les réaliser.
- Routing : Les messages sont distribués dans les queues en fonction de leur type.
La compréhension de RabbitMQ se limite à deux concepts :
- la queue : c'est une file virtuelle de type FIFO dans laquelle des clients vont venir déposer ou récupérer des messages.
- l'exchange : c'est une sorte de routeur qu'un émetteur va créer et dans lequel il va déposer des messages. Sa fonction de routeur réside dans le fait que l'on peut configurer la manière dont il va diffuser les messages. Par exemple, je fais suivre tout les messages de type "error" dans toutes les queues dont le nom correspond au partern "*error*".
Dans les faits, les émetteurs créent des exchanges dans lesquelles ils publient des messages. Les récepteurs eux, viennent brancher des queues aux exchanges pour récupérer les messages.
Infrastructure mise en place
Haute disponibilité
Pour se prémunir d'une éventuelle panne d'un serveur RabbitMQ et pour garantir une disponibilité du service, RabbitMQ propose un système de cluster. Dans notre application deux serveurs RabbitMQ forme un cluster. La réplication des queues de message peut être configurée. Dans notre cas nous avons fait le choix du répliquer par défaut toutes les queues présentes.
Sécurité
L'accès au service de RabbitMQ est sécurisé par des crédentials. Deux utilisateurs existent : spark_user et neo4j_user. Les services souhaitant publier des messages au sein du cluster doivent obligatoirement être authentifiés auprès de ce dernier. Dans le cas contraire, la requête est rejetée. Là encore les droits applicable sur les utilisateurs peuvent être configurés (droit en lecture, droit en écriture, type de queue, espace virtuel, etc...). Dans notre application nous n'avons pas configuré de droit spécifique car un isolement plus fin n'était pas pertinent.
Répartition de charge / DNS
Malgré la présence d'un cluster RabbitMQ, un client qui souhaite poster/récupérer un message doit quand même spécifier le serveur sur lequel il doit se connecter. Pour supprimer au sein des clients l'intelligence de se connecter sur un serveur A ou B suivant les machines disponibles, nous avons mis en place un load balancer, ici HaProxy. Ce dernier a la responsabilité de rediriger et répartir les requêtes en fonction des machines disponibles qu'il connait. Ainsi, les clients ne se posent plus de questions. Ils n'ont à connaître qu'une seule adresse/port. Bien sur ce choix technique est critiquable. En effet, si la machine qui héberge le load balancer tombe, nous aurons une indisponibilité de service. Mais c'est un choix que nous avons fait pour décharger les clients de la problématique décrite plus haut.
Monitoring
Sur les deux machines rabbitmq-1 et rabbitmq-2 un Monit est installé. Il surveille l'état de certains services et est capable, lorsqu'il le détecte, de redémarrer les services qui seraient potentiellement hors service. La configuration de la surveillance est la suivante :
- rabbitmq-1 : rabbitmq-server et haproxy ;
- rabbitmq-2 : rabbitmq-server.
De plus, une interface de management est disponible. Elle permet de voir plusieurs paramètres concernant le cluster:
- état du cluster ;
- queue/exhange en cours ;
- connections en cours ;
- activité en lecture et écriture ;
- poster/lire des messages ;
- etc ...
Cette interface web est disponible via l'url http://[rabbitmq-1|rabbitmq-2]:15672
Déploiement
Le déploiement des serveurs, du HaProxy et du Monit est totalement automatisé et est assuré par des scripts python. Le déroulement de cette phase est la suivante :
Remarques:
- La récupération du Erlang cookie de rabbitmq-1 par rabbitmq-2 est une condition nécessaire pour permettre la formation du cluster.
- La configuration des utilisateurs et des paramètres de réplication n'est obligatoire que sur un serveur. En effet, lors de la création du cluster les serveurs se synchronisent.
Rôle applicatif
Dans notre application, RabbitMQ fait le lien entre les demandes de recommandation pour un utilisateur faites par Mazerunner API et le calcul de la recommandation calculer par orchestrator/jobSpark. Il y a donc 2 exchanges et 2 queues (jobs_to_do et jobs_done). Le schéma suivant résume son rôle: