Pergunta

Por que Redis para fila?

Tenho a impressão de que o Redis pode ser um bom candidato para implementar um sistema de filas.Até agora usamos nosso banco de dados MySQL com polling, ou RabbitMQ.Com o RabbitMQ tivemos muitos problemas - as bibliotecas cliente são muito ruins e cheias de erros e gostaríamos de não investir muitas horas de desenvolvedor para corrigi-las, alguns problemas com o console de gerenciamento do servidor, etc.E, pelo menos por enquanto, não estamos nos agarrando a milissegundos ou aumentando seriamente o desempenho; portanto, desde que um sistema tenha uma arquitetura que suporte uma fila de forma inteligente, provavelmente estaremos em boa forma.

Ok, então esse é o pano de fundo.Essencialmente, tenho um modelo de fila simples e muito clássico - vários produtores produzindo trabalho e vários consumidores consumindo trabalho, e tanto produtores quanto consumidores precisam ser capazes de escalar de forma inteligente.Acontece que é um ingênuo PUBSUB não funciona, já que eu não quero todos assinantes para consumir trabalho, eu só quero um assinante para receber o trabalho.À primeira vista, parece-me que BRPOPLPUSH é um design inteligente.

Podemos usar BRPOPLPUSH?

O projeto básico com BRPOPLPUSH é que você tem uma fila de trabalho e uma fila de progresso.Quando um consumidor recebe trabalho, ele empurra atomicamente o item para a fila de progresso e, quando conclui o trabalho, ele LREM'sentar.Isso evita o bloqueio do trabalho caso os clientes morram e torna o monitoramento bastante fácil - por exemplo, podemos saber se há um problema que faz com que os consumidores demorem muito para realizar as tarefas, além de saber se há um grande volume de tarefas.

Isso garante

  • o trabalho é entregue a exatamente um consumidor
  • o trabalho acaba em uma fila de progresso, então não pode ficar negro se um consumidor

As desvantagens

  • Parece-me um tanto estranho que o melhor design que encontrei não use realmente PUBSUB já que parece ser nisso que a maioria das postagens de blog sobre filas no Redis se concentra.Então sinto que estou perdendo algo óbvio.A única maneira que vejo de usar PUBSUB sem consumir tarefas duas vezes é simplesmente enviar uma notificação de que o trabalho chegou, que os consumidores podem então não bloquear RPOPLPUSH.
  • É impossível solicitar mais de um item de trabalho por vez, o que parece ser um problema de desempenho.Não é grande para a nossa situação, mas obviamente diz que esta operação não foi projetada para alto rendimento ou esta situação
  • Resumidamente: estou perdendo alguma coisa estúpida?

Adicionando também a tag node.js, porque essa é a linguagem com a qual estou lidando principalmente.O Node pode oferecer algumas simplificações na implementação, dada a sua natureza de thread único e sem bloqueio, mas, além disso, estou usando a biblioteca node-redis e as soluções devem ou podem ser sensíveis aos seus pontos fortes e fracos também.

Foi útil?

Solução

Se você quiser usar o Redis para uma fila de mensagens no Node.js e não se importar em usar um módulo para isso, você pode tentar RSMQ - a fila de mensagens simples do Redis para Node.Não estava disponível no momento em que esta pergunta foi feita, mas hoje é uma opção viável.

Se você quiser realmente implemento a fila como você declarou em sua pergunta, então você pode querer ler a fonte do RSMQ porque são apenas 20 telas de código que fazem exatamente o que você está pedindo.

Ver:

Outras dicas

Encontrei algumas dificuldades até agora que gostaria de documentar aqui.

Como você lida com a lógica de reconexão?

Este é um problema difícil e especialmente difícil no projeto e implementação de uma fila de mensagens.As mensagens devem poder ficar na fila em algum lugar quando os consumidores estão offline, portanto, um simples pub-sub não é forte o suficiente e os consumidores precisam se reconectar em estado de escuta. Os pops de bloqueio são um estado difícil de manter, porque são um estado de escuta não idempotente.A escuta deve ser uma operação idempotente, mas ao lidar com uma desconexão em relação a um pop de bloqueio, você tem o prazer de pensar muito sobre se a desconexão aconteceu logo após a operação ter sido bem-sucedida ou pouco antes da operação falhar.Isso não é intransponível, mas é indesejável.

Além disso, a operação de escuta deve ser tão simples quanto possível. Idealmente, deveria ter estas propriedades:

  • Ouvir é idempotente.
  • O consumidor é sempre a escuta e a lógica de limitação são processadas fora do código lógico de escuta.O RabbitMQ encapsula isso permitindo que o consumidor limite o número de mensagens não confirmadas que ele pode ter.
    Em particular, optei por um design pobre, no qual a reentrada em um pop de bloqueio dependia do sucesso de operações anteriores, que era frágil e exigia muita reflexão.

Agora estou favorecendo uma solução Redis PUBSUB + RPOPLPUSH.Isso separa a notificação de trabalho do consumo de trabalho, o que nos permite considerar uma solução de escuta limpa. O PUBSUB é responsável apenas pela notificação dos trabalhos. A natureza atômica do RPOPLPUSH é responsável pelo consumo e pela delegação de trabalho a exatamente um consumidor.No início, esta solução parecia desnecessariamente complicada em comparação com um bloqueio pop, mas agora vejo que a complicação não era desnecessária;estava resolvendo um problema difícil.

No entanto, esta solução não é tão trivial:

  • os consumidores também devem verificar se há trabalho na reconexão.
  • de qualquer maneira, os consumidores podem querer fazer uma pesquisa para novos trabalhos, para redundância.Caso a enquete realmente tenha sucesso, um aviso deverá ser emitido, pois isso só deverá acontecer entre o consumo no PUBSUB e a enquete em um RPOPLPUSH.Portanto, muitos sucessos nas pesquisas indicam um sistema de assinatura falido.

Observe que o design PUBSUB/RPOPLPUSH também apresenta problemas de dimensionamento. Todo consumidor recebe uma notificação leve de todo mensagem, o que significa que há um gargalo desnecessário.Suspeito que seja possível usar canais para fragmentar o trabalho, mas esse é provavelmente um design complicado de funcionar bem.

Portanto, o maior motivo para escolher usar o RabbitMQ em vez do Redis são os cenários de falha e o clustering.

Este artigo realmente explica melhor, então vou apenas fornecer o link:

https://aphyr.com/posts/283-jepsen-redis

O Redis Sentinel e, mais recentemente, o Redis Clustering não são capazes de lidar com uma série de cenários de falha muito básicos que o tornam uma má escolha para uma fila.

RabbitMQ tem seu próprio conjunto de problemas, no entanto, é incrivelmente sólido na produção e é uma boa fila de mensagens.

Aqui está a postagem para coelho:

https://aphyr.com/posts/315-jepsen-rabbitmq

Quando você olha para o teorema CAP (consistência, disponibilidade e manipulação de partições), você só pode escolher 2 de 3.Estamos aproveitando o RMQ para o CP (manipulação de consistência e partição) com nossa carga de mensagens, se não estivermos disponíveis não será o fim do mundo.Para não perder mensagens, usamos ignore para o tratamento da partição para não perder mensagens.As duplicatas podem ser tratadas, pois a origem gerencia o UUID.

Licenciado em: CC-BY-SA com atribuição
scroll top