J'ai l'impression que Redis peut faire un bon candidat pour l'implémentation d'un système de file d'attente. Jusqu'à présent, nous avons utilisé notre base de données MySQL avec interrogation, ou RabbitMQ. Avec RabbitMQ, nous avons eu de nombreux problèmes - les bibliothèques clientes sont très pauvres et boguées et nous aimerions ne pas investir trop d'heures de développement pour les corriger, quelques problèmes avec la console de gestion du serveur, etc. Et, pour le moment étant au moins, nous ne saisissons pas les millisecondes ou n'augmentons pas sérieusement les performances, donc tant qu'un système a une architecture qui prend en charge une file d'attente intelligemment, nous sommes probablement en bonne forme.
D'accord, c'est donc l'arrière-plan. Essentiellement, j'ai un modèle de file d'attente simple et très classique - plusieurs producteurs produisant du travail et plusieurs consommateurs consommant du travail, et les producteurs et les consommateurs doivent pouvoir évoluer intelligemment. Il s'avère qu'un PUBSUB
naïf ne fonctionne pas, car je ne veux pas que tous les abonnés consomment du travail, je veux juste n que l'abonné reçoive le travail. Au premier passage, il me semble que BRPOPLPUSH
est une conception intelligente.
La conception de base avec BRPOPLPUSH
est que vous avez une file d'attente de travail et une file d'attente de progression. Lorsqu'un consommateur reçoit du travail, il pousse atomiquement l'élément dans la file d'attente de progression et lorsqu'il termine le travail, c'est LREM
. Cela empêche le blackholing du travail si les clients meurent et rend la surveillance assez facile - par exemple, nous pouvons dire s'il y a un problème obligeant les consommateurs à prendre beaucoup de temps pour effectuer des tâches, en plus de dire s'il y a un grand volume de tâches.
Il assure
PUBSUB
car c'est ce sur quoi la plupart des articles de blog sur la mise en file d'attente sur Redis se concentrent. J'ai donc l'impression de manquer quelque chose d'évident. La seule façon que je vois d'utiliser PUBSUB
sans consommer deux fois les tâches est simplement de pousser une notification indiquant que le travail est arrivé, que les consommateurs peuvent ensuite sans blocage RPOPLPUSH
.Ajout également de la balise node.js, car c'est la langue avec laquelle je traite le plus. Node peut offrir quelques simplifications dans l'implémentation, compte tenu de sa nature à thread unique et non bloquant, mais en outre j'utilise la bibliothèque node-redis et les solutions devraient ou peuvent être sensibles à ses forces et faiblesses comme bien.
Si vous souhaitez utiliser Redis pour une file d'attente de messages dans Node.js et que cela ne vous dérange pas d'utiliser un module pour cela, vous pouvez essayer RSMQ - le Redis File d'attente de messages simple pour le nœud. Il n'était pas disponible au moment où cette question a été posée, mais aujourd'hui, c'est une option viable.
Si vous voulez réellement implémenter la file d'attente vous-même comme vous l'avez dit dans votre question, alors vous voudrez peut-être lire la source de RSMQ car ce ne sont que 20 écrans de code qui fait exactement ce que vous demandez.
Voir:
J'ai rencontré des difficultés jusqu'à présent, je voudrais documenter ici.
C'est un problème difficile et un problème particulièrement difficile dans la conception et la mise en œuvre d'une file d'attente de messages. Les messages doivent pouvoir être mis en file d'attente quelque part lorsque les consommateurs sont hors ligne, donc un simple pub-sub n'est pas assez fort, et les consommateurs doivent se reconnecter dans un état d'écoute. Les pops bloquants sont un état difficile à maintenir, car ils sont un état d'écoute non idempotent. L'écoute devrait être une opération idempotente, mais lorsque vous avez affaire à une déconnexion par rapport à un blocage pop, vous avez le plaisir de réfléchir très attentivement à savoir si la déconnexion s'est produite juste après la réussite de l'opération ou juste avant l'échec de l'opération. Ce n'est pas insurmontable, mais c'est indésirable.
De plus, l'opération d'écoute devrait être aussi simple que possible. Idéalement, elle devrait avoir les propriétés suivantes:
Je suis maintenant en faveur d'une solution Redis PUBSUB + RPOPLPUSH. Cela dissocie la notification du travail de la consommation du travail, ce qui nous permet de prendre en compte une solution d'écoute propre. Le PUBSUB est uniquement responsable de la notification des travaux. La nature atomique de RPOPLPUSH est responsable de la consommation et de la délégation du travail à exactement un consommateur. Au début, cette solution semblait inutilement compliquée par rapport à un pop bloquant, mais maintenant je vois que la complication n'était pas inutile du tout; il résolvait un problème difficile.
Cependant, cette solution n'est pas tout à fait triviale:
Notez que la conception PUBSUB/RPOPLPUSH a également des problèmes de mise à l'échelle. Chaque consommateur reçoit une notification légère de chaque message, ce qui signifie qu'il y a un goulot d'étranglement inutile. Je soupçonne qu'il est possible d'utiliser des canaux pour partager le travail, mais c'est probablement une conception délicate pour bien fonctionner.
Ainsi, la principale raison de choisir d'utiliser RabbitMQ sur Redis est les scénarios de défaillance et le clustering.
Cet article l'explique vraiment mieux, donc je vais simplement fournir le lien:
https://aphyr.com/posts/283-jepsen-redis
Redis sentinel et plus récemment redis clustering ne sont pas en mesure de gérer un certain nombre de scénarios de défaillance très basiques qui en ont fait un mauvais choix pour une file d'attente.
RabbitMQ a son propre ensemble de problèmes, mais cela étant dit, il est incroyablement solide en production et constitue une bonne file d'attente de messages.
Voici le post pour le lapin:
https://aphyr.com/posts/315-jepsen-rabbitmq
Lorsque vous regardez le théorème CAP (cohérence, disponibilité et gestion des partitions), vous ne pouvez en choisir que 2 sur 3. Nous tirons parti de RMQ pour le CP (cohérence et gestion des partitions) avec notre chargement de message, si nous ne sommes pas disponibles, ce n'est pas le cas. t la fin du monde. Afin de ne pas perdre de messages, nous utilisons ignore pour la gestion de la partition afin de ne pas perdre de messages. Les doublons peuvent être traités car la source gère l'UUID.