Quand utiliser Redis comme courtier de messages ?
Découvrez les scénarios idéaux pour utiliser Redis comme courtier de messages grâce à ses deux fonctionnalités principales : Pub/Sub et Streams. Ce guide complet détaille les avantages en termes de performances, la faible latence et les bénéfices d'infrastructure de la messagerie Redis. Apprenez les différences cruciales entre Pub/Sub éphémère et Streams durables, comprenez leurs limites par rapport aux courtiers dédiés comme Kafka, et trouvez des cas d'utilisation concrets — de la simple invalidation de cache aux files de tâches légères et robustes — pour vous aider à choisir l'outil adapté à vos besoins de communication asynchrone.
Quand utiliser Redis comme courtier de messages ?
Redis peut être un bon courtier de messages lorsque la tâche est petite, rapide et proche des données que vous stockez déjà dans Redis. Il peut aussi être le mauvais outil si vous avez besoin de fortes garanties de livraison, d'une longue rétention, de fonctionnalités de routage, ou d'un courtier qui continue de fonctionner confortablement lorsque l'historique des messages est bien plus volumineux que la mémoire.
La décision devient plus facile si vous arrêtez de vous demander « Redis peut-il faire de la messagerie ? » et que vous vous demandez « Quelle primitive de messagerie Redis correspond au mode de défaillance que je peux tolérer ? »
Redis vous offre plusieurs modèles, mais deux sont les plus importants pour cette question :
- Pub/Sub pour les diffusions en direct.
- Streams pour le traitement durable des messages, de type journal, avec des groupes de consommateurs.
Ils se ressemblent de loin. Ils ne se ressemblent pas opérationnellement.
Utilisez Pub/Sub lorsque perdre un message est acceptable
Redis Pub/Sub est une diffusion en direct. Un éditeur envoie un message sur un canal. Les abonnés connectés reçoivent le message. Redis ne stocke pas ce message pour les abonnés déconnectés, et il n'y a pas d'accusé de réception intégré.
C'est parfait pour certains travaux :
SUBSCRIBE cache:invalidations
PUBLISH cache:invalidations 'product:123'
Si une instance d'application manque cette invalidation parce qu'elle a redémarré au mauvais moment, le monde ne devrait pas s'arrêter. Le cache local doit avoir des TTL, des vérifications de version, ou un autre moyen de récupération. Pub/Sub est un chemin de notification, pas la source de vérité.
Bons cas d'utilisation de Pub/Sub :
- Invalidation de cache entre instances d'application.
- Mises à jour d'interface utilisateur en direct où les clients ne se soucient que de l'état actuel.
- Signaux de présence comme « l'utilisateur tape » ou « le battement de cœur du travailleur a changé ».
- Notifications légères de déploiement ou de changement de configuration.
- Événements de diffusion où les messages manqués sont tolérables.
Mauvais cas d'utilisation de Pub/Sub :
- Traitement des paiements.
- Tâches d'e-mail qui doivent finalement être envoyées.
- Mises à jour d'inventaire qui ne doivent pas être ignorées.
- Journaux d'audit.
- Tout ce où un consommateur déconnecté doit rattraper son retard plus tard.
Pub/Sub est rapide parce qu'il fait moins de choses. C'est le compromis.
Utilisez Streams lorsque les consommateurs doivent rattraper leur retard
Redis Streams stocke les entrées dans une structure de données de flux :
XADD orders:events * order_id 42 status paid
Les consommateurs peuvent lire à partir d'une position :
XREAD COUNT 10 STREAMS orders:events 0
Les groupes de consommateurs permettent à plusieurs travailleurs de partager le travail :
XGROUP CREATE orders:events order-workers 0 MKSTREAM
XREADGROUP GROUP order-workers worker-1 COUNT 10 STREAMS orders:events >
XACK orders:events order-workers 1740000000000-0
Avec les groupes de consommateurs, un message livré à un travailleur reste dans la liste des entrées en attente jusqu'à ce qu'il soit acquitté avec XACK. Si un travailleur meurt après avoir lu mais avant d'acquitter, un autre travailleur peut inspecter et réclamer le travail en attente. Cela vous donne un traitement au moins une fois lorsque vous construisez correctement le consommateur.
Au moins une fois signifie que les doublons sont possibles. Votre travailleur doit être idempotent. Par exemple, un travailleur d'e-mail doit enregistrer que email_job_id=abc123 a été envoyé avant de tenter de l'envoyer à nouveau. Un travailleur de commande doit éviter de facturer deux fois s'il voit la même entrée de flux deux fois.
Bons cas d'utilisation de Streams :
- Tâches d'arrière-plan légères.
- Événements de service internes qui nécessitent une relecture après de courtes pannes.
- Journaux d'événements de petite à moyenne taille.
- Pools de travailleurs où chaque tâche doit être traitée par un seul travailleur dans un groupe.
- Flux d'activité ou journaux de changement d'état avec une rétention limitée.
Les Streams ne sont pas gratuits. Les entrées vivent dans la mémoire de Redis, sauf si elles sont élaguées ou expirées par votre conception. Si vous n'élaguez jamais un flux actif, le flux devient votre prochain incident mémoire.
Utilisez l'élagage :
XADD orders:events MAXLEN ~ 100000 * order_id 42 status paid
XTRIM orders:events MAXLEN ~ 100000
L'élagage approximatif avec ~ est généralement moins coûteux que l'élagage exact. Choisissez la rétention en fonction des besoins de récupération, pas de l'espoir.
Les listes Redis sont toujours utiles pour les files d'attente simples
Avant l'existence des Streams, de nombreuses files d'attente Redis utilisaient des listes :
LPUSH jobs:email '{"to":"[email protected]"}'
BRPOP jobs:email 5
Les listes sont toujours adaptées pour les files d'attente très simples, surtout lorsque vous avez besoin d'un comportement de blocage et que vous n'avez pas besoin de groupes de consommateurs ou d'historique. La limite est la récupération. Si un travailleur extrait une tâche et plante avant de la terminer, cette tâche est perdue à moins que vous n'ajoutiez une comptabilité supplémentaire.
Il existe des modèles utilisant BRPOPLPUSH ou BLMOVE pour déplacer les tâches dans une liste de traitement, puis les supprimer après succès. Ces modèles peuvent fonctionner, mais une fois que vous avez besoin de suivi des tâches en attente, de tentatives et de plusieurs consommateurs, les Streams vous donnent généralement un point de départ plus clair.
Choisissez Redis lorsque la simplicité compte plus que les fonctionnalités du courtier
La messagerie Redis est attrayante lorsque Redis fait déjà partie de votre pile et que la charge de travail est modeste. Vous évitez d'exploiter un autre système distribué. Les développeurs comprennent déjà les clients Redis, la surveillance, les identifiants et les chemins de déploiement.
C'est une raison valable. La simplicité opérationnelle a une réelle valeur.
Redis a également une très faible latence. Si votre application et Redis sont dans la même région ou sur un réseau privé, publier une petite notification est généralement peu coûteux et rapide. Pour l'invalidation de cache ou les mises à jour de statut en direct, un courtier plus lourd peut être inutile.
Redis vous permet également de combiner soigneusement les changements d'état et les messages. Un script Lua ou une transaction peut mettre à jour une clé et ajouter à un flux en une seule opération côté Redis. Cela peut être utile pour les petits systèmes où Redis est le détenteur central de l'état.
Le piège est que Redis ne devrait pas devenir votre courtier accidentel pour tout. Si chaque service commence à ajouter des flux à volume élevé sans plan de rétention, le choix « simple » devient un magasin de journaux en mémoire surchargé.
Choisissez un courtier dédié lorsque la gestion des défaillances est le produit
Kafka, RabbitMQ, Pulsar, NATS JetStream et les services de file d'attente cloud existent parce que la messagerie devient rapidement complexe.
Utilisez un courtier dédié lorsque vous avez besoin de fonctionnalités telles que :
- Longue rétention mesurée en semaines, mois ou années.
- Historique des messages bien plus volumineux que la mémoire.
- Files d'attente de lettres mortes et politiques de tentatives intégrées au courtier.
- Livraison différée, priorités, clés de routage, échanges ou partitionnement de sujets.
- Modèles de réplication inter-régions conçus pour la messagerie.
- De nombreux groupes de consommateurs indépendants rejouant le même historique d'événements.
- Outils plus robustes autour du retard, des décalages, du rééquilibrage et des audits.
Kafka est généralement mieux adapté pour les pipelines d'événements à volume élevé et les journaux rejouables. RabbitMQ est souvent mieux adapté pour le routage sophistiqué, les accusés de réception et les files de travail. Les files d'attente cloud sont souvent meilleures lorsque vous souhaitez une durabilité gérée et des limites opérationnelles simples.
Redis Streams peut gérer des charges de travail de production utiles, mais c'est toujours Redis. Ses données sont centrées sur la mémoire, ses paramètres de persistance doivent être compris, et ses fonctionnalités de courtier sont intentionnellement plus petites que celles des systèmes dédiés.
Une façon concrète de décider
Posez ces questions avant de choisir Redis :
- Un consommateur peut-il manquer un message sans perte de données ?
- Un consommateur déconnecté doit-il rattraper son retard ?
- Combien de temps les messages doivent-ils être conservés ?
- Les données des messages conservés peuvent-elles tenir confortablement dans la mémoire de Redis ?
- Les travailleurs gèrent-ils les messages en double en toute sécurité ?
- Avez-vous besoin de files d'attente de lettres mortes, de tentatives différées, de priorités ou de règles de routage ?
- Ce trafic interférera-t-il avec la mise en cache ou les sessions Redis ?
Si les messages manqués sont acceptables, Pub/Sub peut suffire.
Si les consommateurs ont besoin de rattraper leur retard et que la rétention est limitée, les Streams peuvent suffire.
Si les données des messages nécessitent une longue rétention, une relecture par de nombreuses équipes, un comportement de courtier complexe ou une séparation opérationnelle forte, utilisez un courtier dédié.
Exemple : invalidation de cache
Une application stocke les pages de produits dans la mémoire locale du processus et dans Redis. Lorsqu'un produit change, le service d'administration publie :
PUBLISH cache:invalidate product:123
Chaque instance Web abonnée à cache:invalidate supprime sa copie locale. Si une instance Web manque le message, son entrée locale a toujours un TTL de cinq minutes et elle vérifie également un champ de version du produit lors de la prochaine requête. Pub/Sub est acceptable car il existe un chemin de récupération.
Utiliser Kafka ici ajouterait probablement plus de poids opérationnel que de valeur.
Exemple : tâches d'e-mail en arrière-plan
Un utilisateur s'inscrit et vous devez envoyer un e-mail de bienvenue. Si le travailleur est hors service pendant une minute, la tâche doit toujours être envoyée plus tard. Pub/Sub est un mauvais choix.
Un Stream Redis peut fonctionner :
XADD email:jobs MAXLEN ~ 100000 * job_id abc123 type welcome user_id 42
Les travailleurs lisent via un groupe de consommateurs, envoient l'e-mail, enregistrent job_id comme terminé et appellent XACK. Un moniteur vérifie les tâches en attente et réclame les anciennes. C'est raisonnable pour une file d'attente interne modeste.
Si la livraison d'e-mails devient à grande échelle, nécessite des tentatives différées, une gestion des lettres mortes, des limites de débit par client et des tableaux de bord opérationnels riches, une file d'attente dédiée commence à sembler meilleure.
Exemple : événements d'audit
Les événements d'audit nécessitent généralement durabilité, recherche, rétention et parfois un traitement juridique ou de conformité. Redis Streams peut aider comme tampon court, mais Redis ne devrait pas être le magasin d'audit final. Utilisez un journal durable, une base de données, un pipeline de stockage d'objets ou un service d'événements géré conçu pour la rétention et la révision.
Notes opérationnelles si vous choisissez Redis
Pour Pub/Sub :
- Configurez
client-output-buffer-limit pubsub. - Utilisez des connexions d'abonnés dédiées.
- Construisez un comportement de reconnexion et de réabonnement.
- Traitez les messages comme des indices, pas comme des faits durables.
Pour Streams :
- Définissez une politique de rétention avec
MAXLEN,MINIDou un élagage explicite. - Surveillez les entrées en attente.
- Rendez les consommateurs idempotents.
- Utilisez
XACKuniquement après que le travail a réussi. - Planifiez comment les messages bloqués sont réclamés et retentés.
- Surveillez la mémoire, la persistance et le retard de réplication.
Redis est un bon courtier de messages lorsque vous choisissez la partie de Redis qui correspond à la tâche. Pub/Sub est un signal en direct. Les Streams sont un journal durable limité. Ni l'un ni l'autre ne devrait être choisi simplement parce que Redis est déjà en cours d'exécution, mais les deux peuvent être la réponse correcte la plus simple lorsque leur modèle de défaillance correspond à votre application.
Le terrain d'entente inconfortable
De nombreuses équipes atterrissent au milieu : Pub/Sub est trop sujet aux pertes, Kafka semble trop lourd, et RabbitMQ semble être un système de plus à exploiter. Redis Streams peut être une bonne réponse là, mais seulement si vous le traitez comme une vraie file d'attente et non comme une liste magique.
Une conception saine de Streams a une propriété autour de ces détails :
- Qui crée le flux et le groupe de consommateurs ?
- Combien de consommateurs sont attendus ?
- Quel est l'âge maximal en attente avant qu'un message soit réclamé ?
- Que se passe-t-il après un échec répété ?
- Combien d'historique du flux est conservé ?
- Quel tableau de bord ou alerte montre un retard croissant ?
Sans ces réponses, les Streams peuvent échouer silencieusement. Un travailleur peut lire des messages et planter avant XACK, laissant les entrées en attente pour toujours. Un autre travailleur peut ne jamais les réclamer. La longueur du flux peut continuer à croître parce que personne n'a configuré l'élagage. La mémoire de Redis augmente, mais l'équipe d'application pense que « la file d'attente est durable », donc ils ne remarquent rien jusqu'à ce que l'instance soit sous pression.
Un travailleur simple devrait généralement faire cette boucle :
lire un petit lot
traiter chaque message de manière idempotente
acquitter uniquement les messages réussis
inspecter périodiquement les messages en attente
réclamer les messages en attente obsolètes
élaguer selon la politique de rétention
C'est plus de travail que Pub/Sub, et c'est le but. La durabilité déplace toujours la complexité quelque part. Redis Streams maintient le côté courtier assez petit, mais l'application possède toujours les tentatives, le comportement des lettres mortes et l'idempotence.
Si personne dans l'équipe ne veut posséder ces détails, une file d'attente gérée peut être moins chère à long terme même si elle semble plus lourde le premier jour. Le meilleur courtier n'est pas le plus rapide dans un benchmark. C'est celui dont le comportement en cas de défaillance votre équipe peut opérer à 3 heures du matin sans deviner.