Netty
Dans cette série d’articles, nous allons regarder l’utilisation d’un MOM.
Pour cela nous allons voir très rapidement la théorie, les points d’attention et finir avec des cas d’utilisations dans le deuxième article.
Un MOM nous permet d’envoyer et de recevoir des messages de manière asynchrone afin de découpler le producteur et le récepteur.
Il existe trois modes de fonctionnement principaux (qui peuvent avoir des noms différents selon la norme).
Le producteur envoie un message dans le MOM qui l’envoie à un ou plusieurs consommateurs. Par contre un seul consommateur lit le message.
Il est possible d’avoir plusieurs consommateurs en même temps.
De même pour les producteurs.
Plusieurs producteurs peuvent écrire sur la même file de messages, mais il y a toujours un seul consommateur qui lit le message.
Pour résumer, le message est transmis à 1 seule file de messages identifiée.
Nous utiliserons ce mode d’échange lorsque le message sera traité par un seul consommateur.
Les consommateurs s’abonnent à un topic. Dès qu’un message arrive dans ce topic, il est lu par tous les consommateurs présents à ce moment.
Si un consommateur arrive après (et que la file de messages est non durable), il ne lira que les messages suivants.
Nous utiliserons ce mode d’échange lorsque le message pourra être traité par plusieurs consommateurs. Par exemple pour implémenter des fils d’actualité, des notifications d’événements, etc.
Le producteur envoie un message dans le MOM qui l’envoie à toutes les files de messages qui y sont connectées à ce moment.
Les cas d’utilisation sont les mêmes que pour du broadcast classique.
De nombreuses normes/protocoles existent :
Une fois la norme choisie, il nous reste à choisir le bon outil
Pour vous aider, voici une liste non exhaustive :
Notez que :
Avant d'éventuellement choisir une des solutions (qui offre plein de bonne raison de les utiliser), il est préférable de se poser un peu et de réfléchir aux points suivants.
Quel que soit l’outil utilisé, nous aurons accès à des mesures nous permettant de comprendre son fonctionnement.
Par contre le suivi de bout en bout d’une requête devient plus complexe et doit être pris en compte dès la phase de design.
Par exemple en utilisant le design pattern correlation id qui consiste à l’ajout d’un identifiant dans chaque requête pour suivre une transaction de bout en bout dans le SI.
Ou en utilisant un APM (Application Performance Management) qui supporte la technologie utilisée.
En fonction de l’outil choisi et de comment il est configuré, on devra faire attention à :
Cela implique une autre difficulté : garder une cohérence à terme (qui désigne un modèle dans lequel la cohérence n’est garantie qu’à la « fin », la « fin » étant relative à votre cas d’utilisation).
Une bonne configuration et utilisation de l’outil choisi associé à des messages idempotent pourra faire l’affaire dans de nombreux cas d’utilisation.
Les MOM permettent de faire du synchrone et de l’asynchrone.
Par exemple la fonction de failover d’ActiveMQ peut bloquer le producteur. Et donc il faut une bonne connaissance de l’outil pour ne pas tomber dans les pièges.
Un SPOF (Single Point Of Failure) est une brique du système dont une panne entraîne l'arrêt complet du reste. Et donc si on veut un système résilient, il faut aussi que notre MOM le soit.
Lorsqu’on est en synchrone, le producteur est obligé d’attendre que le consommateur réalise son traitement.
Et donc lorsque la charge va augmenter et si le consommateur ne suit pas, la contention va être au niveau du producteur qui va empiler les tâches à réaliser.
Avec de l’asynchrone, c’est l’inverse, la contention va être au niveau du consommateur, car il va se retrouver avec toutes les tâches à réaliser, car le producteur n’aura pas fait barrage.
Et donc il est important de mettre en place une stratégie de back-pressure.
La stratégie de back-pressure consiste à gérer la réaction d’un système en présence de charge conséquente dans une chaîne de traitement. Sa maîtrise et son utilisation permettent d’augmenter la réactivité et la résilience des systèmes dans des conditions extrêmes.
Par exemple en utilisant la fonctionnalité de Producer Flow Control d’ActiveMQ.
Un “poison message” est un message qui va faire tomber le consommateur.
Par exemple avec un message mal formé ou avec un consommateur bogué qui ne prend pas en charge certains messages (taille, caractères non prévus…).
Le message n’ayant pas été consommé, lorsque le consommateur sera de nouveau disponible, sera traité à nouveau avec les mêmes conséquences (crash du consommateur).
Et ainsi de suite.
Encore une fois, une bonne configuration de la solution nous évitera ce type de problème.
Par exemple en utilisant le mécanisme de Dead Letter Exchanges de RabbitMQ ou de dead-letter queue d’ActiveMQ.
Pour des messages de très grande taille, il est préférable d’utiliser une autre solution (par exemple un ETL ou un batch).
En plus de la taille des messages il faut être prudent avec leur nombre dans la file de messages. Car si ce nombre augmente trop, il y a un risque de consommation élevé de la mémoire et donc d’un crash.
Pour éviter cela, il y a plusieurs solutions :
Persister les messages sur disque/base de données, au prix d’une perte de performance, peut éviter de perdre des messages en cas de crash (sauf bien sûr si le disque/base de données crash aussi).
Quelle que soit la solution retenue, une supervision de cette métrique sera toujours utile.
Pour cela il existe plusieurs solutions :
Une des solutions pour implémenter le design pattern Asynchronous data exchanges est d’utiliser un MOM.
Nous avons vu le fonctionnement d’un MOM (point à point, publish/subscribe) et quelques outils.
Petit rappel l’ajout d’un MOM et d’appel asynchrone dans une application n’est pas anodin et donc il faut que cela réponde à un vrai besoin.
Cas d’utilisation que nous verrons dans le prochain article.
Pour aller plus loin, notre nouveau livre blanc sur le sujet vient de sortir :