Qu’est-ce qu’un message broker ?

De Olivier Haag dans Technique

30 juil 2018

Vous est-il déjà arrivé de vouloir commander un ticket pour le concert de votre artiste préféré en ligne via un unique site web qui ne répond pas ?
De vouloir envoyer un gros fichier CSV dont le traitement automatisé vous bloque toute autre action durant ce traitement via un beau message “Chargement…” ? Attendre une vidéo qui met du temps à se ré-encoder après téléchargement sur la toile ?

Tous ces problèmes peuvent s’expliquer par plusieurs facteurs: la surcharge d’utilisateurs simultanés, un algorithme très chronophage incontournable, une architecture peu performante due à son ancienneté.

Il existe plusieurs façons connues pour pallier ces désagréments comme la mise en place de cache, ou l’optimisation de code quand c’est possible. Nous allons nous concentrer sur ce qu’est un message broker qu’on appellera aussi MQ comme Message Queueing.

Un MQ sur le principe permet de gérer des files d’attente de messages. Il est possible ainsi de publier un message qui sera donc en attente d’être consommé.
En pratique, comment cela peut nous être utile ? Imaginez que vous envoyez une vidéo de 1Go sur une plateforme de streaming. En plus du temps qu’il vous faudra pour télécharger le fichier sur le site, ce dernier doit compresser et aussi réencoder la vidéo afin que les futurs spectateurs n’aient pas à télécharger 1Go pour visionner celle-ci. Ce procédé peut être très long. Ainsi il est préférable de dire à l’utilisateur que sa vidéo a bien été reçue et qu’elle sera bientôt disponible. Pour cela l’application publie un message dans la file d’attente dédiée à l’action suivante : encoder la vidéo. Le message est ensuite consommé (quand les ressources sont disponibles), ce qui déclenche l’encodage.

 

Comment ça marche ?

Pour pouvoir gérer des files d’attente, il faut un serveur de message.

Il en existe une multitude (ActiveMQ, Kafka, RabbitMQ, OMS, JMS, Redis, Service Bus, …). Certains comme Redis n’ont pas été créés spécifiquement pour cela mais peuvent servir dans ce même but. Nous allons nous concentrer que sur RabbitMQ qui est une solution très connue et qui s’intègre dans de nombreux langages.

RabbitMQ supporte le protocole AMQP dont l’objectif est de standardiser les échanges entre serveurs de messages. Ainsi toute interaction avec le serveur se fera au travers de ce protocole.

Sur ce serveur, plusieurs éléments devront être paramétrés pour réaliser notre tâche:

  • Un producteur (producer/publisher) : qui publiera (publish) les messages
  • Une file d’attente (queue) : qui cumulera les messages en attente de leur traitement
  • Un consommateur (consumer/subscriber) : qui attendra des messages dans la file à laquelle il sera rattaché puis les traitera (consume)
  • Un exchange : là où seront publiés les messages

Là où un producteur ne représente qu’une instruction de plus appelée par le serveur web afin d’envoyer le message, un consommateur nécessite un processus à part entière (worker) qui attendra en boucle de nouveaux messages pour les traiter un par un.

Le problème étant que s’il faut 10 secondes pour traiter un message; imaginons que 5 messages soient envoyés en même temps, il faudra 50 secondes au dernier message pour être consommé.

Pour résoudre cela il est possible de lancer simultanément plusieurs workers.

Par défaut, RabbitMQ enverra chaque message au consommateur suivant afin de répartir la charge : donc une distribution des messages de type Round-robin.

 

Ainsi avec 2 consommateurs, là où il nous fallait 50 secondes pour traiter la dernière vidéo, ils n’en faut désormais plus que 30.

Il est possible de lancer autant de processus que souhaités. Le but est de trouver un compromis permettant de garder un taux d’occupation élevé de processus et d’en avoir le plus possible sans pour autant saturer les ressources du ou des serveurs qu’ils utilisent. En effet, l’un des avantages de ce découplage est que les processus peuvent être sur des machines différentes.

 

Pour l’instant nous parlions d’envoyer des messages directement dans des files d’attente elles-mêmes liées à des consommateurs spécifiques.

AMQP nous permet également de publier un message sans pour autant en définir la cible en utilisant le patron de publication-souscription. En effet il suffit de publier un message avec par exemple la nature du message qui servira de clé de routage pour que ce dernier soit publié directement dans la bonne file d’attente à laquelle aura souscrit un consommateur.

Au lieu de publier le message directement dans des files d’attente, celui-ci sera publier sur un exchange dont le but sera de diffuser le message pour toutes les files d’attente intéressées.

Il est alors possible d’imaginer des systèmes comme ceci :

Dans ce cas, nous observons que des logs sont répartis dans 2 consommateurs.

On remarque qu’un consommateur reçoit l’ensemble des messages (info, error, warning) et qu’un autre reçoit également les messages d’erreurs. Cela permettra par exemple de fournir un traitement standard avec le premier : stocker les messages dans des fichiers; mais également d’envoyer un mail avec le second lorsqu’une erreur survient.

C’est là tout ce qu’il y a besoin de savoir pour le fonctionnement de base d’un MQ.

Dans quel cas l’utiliser ?

Comme mentionné dans l’introduction, un MQ peut être utile lorsque des traitements rendent le traitement direct trop gênant à attendre. De manière générale, c’est tout de même une solution assez impactante et peut être exagérée en dessous d’un certain nombre de données. De manière générale, sa nécessité peut apparaître lorsque des milliers voire milliards de messages doivent être échangés.

Ceci coïncide par exemple bien avec l’Internet des objets (IoT).

Quels sont ses avantages et désavantages ?

Une telle infrastructure, de par son fonctionnement, oriente fortement vos applications vers une programmation événementielle.

Ceci a pour avantage de découpler vos applications, ce qui permet non seulement de paralléliser les développements avec un risque minime mais aussi de les rendre plus modulables : plus propices à l’évolution, au changement.

Les messages étant stockés le temps que le traitement se fasse, une interruption du serveur n’entraîne donc pas la perte d’un traitement en cours.

De plus, cela permet aussi une meilleure scalabilité réduisant ainsi les problématiques de performance déjà mentionnées.

Le plus gros désavantage réside cependant dans un effet secondaire de son principal avantage : le découplage.

En effet un producteur publiera des messages en supposant qu’un consommateur les traite par la suite. En pratique, rien n’affirme ce prédicat et c’est d’ailleurs un des premiers problèmes que vous allez rencontrer en développant ce genre de systèmes :

“Pourquoi je ne reçois pas le mail ? Mince ! Le consumer ne tourne plus”.

Tout comme quand vous envoyez un courrier par la poste, si la voiture du facteur brûle, votre courrier n’arrivera pas. Ainsi, si un consumer s’arrête suite à une erreur inattendue, le message n’arrivera pas non plus. Cela peut être compensé par l’ajout d’un accusé de réception (ACK), mais cela se fait au détriment de la scalabilité couplant ainsi à nouveau producteur et consommateur.

L’impact porte également sur l’expérience utilisateur. Bien qu’on puisse se débarrasser potentiellement de chargements, il faut désormais incorporer dans l’interface la notion de ressource en cours de traitement voire du suivi d’une tâche (d’un colis ?).

Conclusion

Un message broker est une solution qui s’accompagne de concepts qui en font un projet assez conséquent à concevoir rigoureusement. Mais celle-ci reste très intéressante pour améliorer les performances et l’évolution à grande échelle de vos applications ou de votre SI.

Bibliographie

Commentaire

sept − 2 =

iMDEO recrute !

REJOIGNEZ-NOUS

A la recherche de nouveaux talents (développeurs web et mobile, chefs de projet,...)

Voir les annonces