¿Por qué Redis para hacer cola?
Tengo la impresión de que Redis puede ser un buen candidato para implementar un sistema de colas. Hasta este momento, hemos estado utilizando nuestra base de datos MySQL con sondeo, o RabbitMQ. Con RabbitMQ hemos tenido muchos problemas: las bibliotecas del cliente son muy pobres y tienen errores y nos gustaría no invertir demasiadas horas de desarrollador en solucionarlos, algunos problemas con la consola de administración del servidor, etc. Y, por el momento siendo al menos, no estamos tratando de alcanzar milisegundos o presionando seriamente el rendimiento, por lo que mientras un sistema tenga una arquitectura que soporte una cola de manera inteligente, probablemente estemos en buena forma.
Bien, ese es el trasfondo. Esencialmente tengo un modelo de cola muy clásico y simple: varios productores que producen trabajo y varios consumidores que consumen trabajo, y tanto los productores como los consumidores deben poder escalar de manera inteligente. Resulta que un ingenuo PUBSUB
no funciona, ya que no quiero que todos los suscriptores consuman trabajo, solo quiero que un suscriptor reciba el trabajo. A primera vista, me parece que BRPOPLPUSH
es un diseño inteligente.
¿Podemos usar BRPOPLPUSH?
El diseño básico BRPOPLPUSH
es que tiene una cola de trabajo y una cola de progreso. Cuando un consumidor recibe trabajo, empuja atómicamente el elemento a la cola de progreso, y cuando completa el trabajo, LREM
es él. Esto evita el bloqueo del trabajo si los clientes mueren y hace que el monitoreo sea bastante fácil; por ejemplo, podemos saber si hay un problema que hace que los consumidores tomen mucho tiempo para realizar tareas, además de saber si hay un gran volumen de tareas.
Se asegura
- el trabajo se entrega exactamente a un consumidor
- el trabajo termina en una cola de progreso, por lo que no puede bloquearse si un consumidor
Los inconvenientes
- Me parece bastante extraño que el mejor diseño que he encontrado en realidad no lo use,
PUBSUB
ya que esto parece ser en lo que se enfoca la mayoría de las publicaciones de blog sobre hacer cola en Redis. Entonces siento que me falta algo obvio. La única forma que veo de usarPUBSUB
sin consumir tareas dos veces es simplemente enviar una notificación de que el trabajo ha llegado, que los consumidores pueden sin bloquearRPOPLPUSH
. - Es imposible solicitar más de un elemento de trabajo a la vez, lo que parece ser un problema de rendimiento. No es muy importante para nuestra situación, pero obviamente dice que esta operación no fue diseñada para un alto rendimiento o esta situación
- En resumen: ¿me estoy perdiendo algo estúpido?
También agrego la etiqueta node.js, porque ese es el lenguaje con el que estoy tratando principalmente. Node puede ofrecer algunas simplificaciones en la implementación, dada su naturaleza de subproceso único y no bloqueante, pero además estoy usando la biblioteca de nodo-redis y las soluciones deberían o pueden ser sensibles a sus fortalezas y debilidades también.
fuente
Me he topado con algunas dificultades hasta ahora que me gustaría documentar aquí.
¿Cómo manejas la lógica de reconexión?
Este es un problema difícil y un problema especialmente difícil en el diseño e implementación de una cola de mensajes. Los mensajes deben poder hacer cola en algún lugar cuando los consumidores están desconectados, por lo que un simple pub-sub no es lo suficientemente fuerte y los consumidores deben volver a conectarse en un estado de escucha. El bloqueo de pops es un estado difícil de mantener, porque son un estado de escucha no idempotente . Escuchar debe ser una operación idempotente, pero cuando se trata de una desconexión con respecto a un pop de bloqueo, tiene el placer de pensar mucho sobre si la desconexión ocurrió justo después de que la operación tuvo éxito o justo antes de que la operación fallara. Esto no es insuperable, pero es indeseable.
Además, la operación de escucha debe ser lo más simple posible. Idealmente debería tener estas propiedades:
En particular, elegí un diseño deficiente en el que volver a ingresar a un pop de bloqueo dependía del éxito de las operaciones anteriores, que era frágil y requería pensar mucho.
Ahora estoy a favor de una solución Redis PUBSUB + RPOPLPUSH. Esto desacopla la notificación de trabajo del consumo de trabajo, lo que nos permite descifrar una solución de escucha limpia. El PUBSUB solo es responsable de la notificación del trabajo. La naturaleza atómica de RPOPLPUSH es responsable del consumo y de delegar el trabajo exactamente a un consumidor. Al principio, esta solución parecía innecesariamente complicada en comparación con un pop de bloqueo, pero ahora veo que la complicación no era innecesaria en absoluto; Estaba resolviendo un problema difícil.
Sin embargo, esta solución no es del todo trivial:
Tenga en cuenta que el diseño PUBSUB / RPOPLPUSH también tiene problemas de escala. Cada consumidor recibe una notificación ligera de cada mensaje, lo que significa que tiene un cuello de botella innecesario. Sospecho que es posible usar canales para fragmentar el trabajo, pero este es probablemente un diseño complicado para que funcione bien.
fuente
Entonces, la razón más importante para elegir usar RabbitMQ sobre Redis son los escenarios de falla y la agrupación.
Este artículo realmente lo explica mejor, así que solo proporcionaré el enlace:
https://aphyr.com/posts/283-jepsen-redis
Redis Sentinel y más recientemente Redis Clustering no pueden manejar una serie de escenarios de falla muy básicos que lo convirtieron en una mala elección para una cola.
RabbitMQ tiene su propio conjunto de problemas, sin embargo, dicho esto, es increíblemente sólido en producción y es una buena cola de mensajes.
Aquí está la publicación para conejo:
https://aphyr.com/posts/315-jepsen-rabbitmq
Cuando observa el teorio CAP (consistencia, disponibilidad y manejo de particiones) solo puede elegir 2 de 3. Estamos aprovechando RMQ para el CP (consistencia y manejo de particiones) con nuestra carga de mensajes, si no estamos disponibles, no está t el fin del mundo. Para no perder mensajes, usamos ignorar para el manejo de la partición para no perder mensajes. Los duplicados se pueden manejar ya que la fuente administra el UUID.
fuente