¿Cuándo deberías usar Redis como broker de mensajes?
Descubre los escenarios ideales para aprovechar Redis como broker de mensajes utilizando sus dos características principales: Pub/Sub y Streams. Esta guía completa detalla las ventajas de rendimiento, la baja latencia y los beneficios de infraestructura de la mensajería con Redis. Aprende las diferencias cruciales entre Pub/Sub efímero y Streams duraderos, comprende sus limitaciones en comparación con brokers dedicados como Kafka, y encuentra casos de uso prácticos, desde la invalidación simple de caché hasta colas de tareas ligeras y robustas, para ayudarte a elegir la herramienta adecuada para tus necesidades de comunicación asíncrona.
¿Cuándo deberías usar Redis como broker de mensajes?
Redis puede ser un buen broker de mensajes cuando el trabajo es pequeño, rápido y está cerca de los datos que ya guardas en Redis. También puede ser la herramienta equivocada si necesitas garantías de entrega sólidas, retención prolongada, funciones de enrutamiento o un broker que siga funcionando cómodamente cuando el historial de mensajes es mucho más grande que la memoria.
La decisión se vuelve más fácil si dejas de preguntar "¿Puede Redis hacer mensajería?" y preguntas "¿Qué primitiva de mensajería de Redis coincide con el modo de fallo que puedo tolerar?".
Redis te ofrece varios patrones, pero dos son los más importantes para esta pregunta:
- Pub/Sub para transmisiones en vivo.
- Streams para procesamiento de mensajes duradero, tipo registro, con grupos de consumidores.
Se sienten similares desde lejos. No son similares operativamente.
Usa Pub/Sub cuando perder un mensaje sea aceptable
Redis Pub/Sub es una transmisión en vivo. Un publicador envía a un canal. Los suscriptores conectados reciben el mensaje. Redis no almacena ese mensaje para suscriptores desconectados y no hay confirmación incorporada.
Eso es perfecto para algunos trabajos:
SUBSCRIBE cache:invalidations
PUBLISH cache:invalidations 'product:123'
Si una instancia de aplicación pierde esa invalidación porque se reinició en el momento equivocado, el mundo no debería terminar. La caché local debería tener TTLs, comprobaciones de versión u otra forma de recuperarse. Pub/Sub es una ruta de notificación, no la fuente de verdad.
Buenos casos de uso de Pub/Sub:
- Invalidación de caché entre instancias de aplicación.
- Actualizaciones de UI en vivo donde los clientes solo se preocupan por el estado actual.
- Señales de presencia como "el usuario está escribiendo" o "el latido del trabajador cambió".
- Notificaciones ligeras de cambios de configuración o implementación.
- Eventos de difusión donde los mensajes perdidos son tolerables.
Malos casos de uso de Pub/Sub:
- Procesamiento de pagos.
- Trabajos de correo electrónico que deben enviarse eventualmente.
- Actualizaciones de inventario que no deben omitirse.
- Registros de auditoría.
- Cualquier cosa donde un consumidor desconectado deba ponerse al día más tarde.
Pub/Sub es rápido porque hace menos. Ese es el intercambio.
Usa Streams cuando los consumidores necesiten ponerse al día
Redis Streams almacenan entradas en una estructura de datos de flujo:
XADD orders:events * order_id 42 status paid
Los consumidores pueden leer desde una posición:
XREAD COUNT 10 STREAMS orders:events 0
Los grupos de consumidores permiten que varios trabajadores compartan trabajo:
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
Con grupos de consumidores, un mensaje entregado a un trabajador permanece en la lista de entradas pendientes hasta que se confirma con XACK. Si un trabajador muere después de leer pero antes de confirmar, otro trabajador puede inspeccionar y reclamar el trabajo pendiente. Eso te da procesamiento al menos una vez cuando construyes el consumidor correctamente.
Al menos una vez significa que los duplicados son posibles. Tu trabajador debe ser idempotente. Por ejemplo, un trabajador de correo electrónico debe registrar que email_job_id=abc123 se envió antes de intentar enviarlo de nuevo. Un trabajador de pedidos debe evitar cobrar dos veces si ve la misma entrada de flujo dos veces.
Buenos casos de uso de Streams:
- Trabajos en segundo plano ligeros.
- Eventos de servicio internos que necesitan reproducción después de cortes breves.
- Registros de eventos pequeños o medianos.
- Grupos de trabajadores donde cada trabajo debe ser procesado por un trabajador en un grupo.
- Fuentes de actividad o registros de cambios de estado con retención limitada.
Los Streams no son gratuitos. Las entradas viven en la memoria de Redis a menos que se recorten o caduquen según tu diseño. Si nunca recortas un flujo ocupado, el flujo se convierte en tu próximo incidente de memoria.
Usa el recorte:
XADD orders:events MAXLEN ~ 100000 * order_id 42 status paid
XTRIM orders:events MAXLEN ~ 100000
El recorte aproximado con ~ suele ser más barato que el recorte exacto. Elige la retención según las necesidades de recuperación, no según la esperanza.
Las listas de Redis siguen siendo útiles para colas simples
Antes de que existieran los Streams, muchas colas de Redis usaban listas:
LPUSH jobs:email '{"to":"[email protected]"}'
BRPOP jobs:email 5
Las listas siguen siendo adecuadas para colas muy simples, especialmente cuando necesitas un comportamiento de bloqueo pop y no necesitas grupos de consumidores ni historial. La limitación es la recuperación. Si un trabajador saca un trabajo y falla antes de terminar, ese trabajo se pierde a menos que agregues una contabilidad adicional.
Existen patrones que usan BRPOPLPUSH o BLMOVE para mover trabajos a una lista de procesamiento y luego eliminarlos después del éxito. Esos patrones pueden funcionar, pero una vez que necesitas seguimiento de pendientes, reintentos y múltiples consumidores, los Streams suelen darte un punto de partida más claro.
Elige Redis cuando la simplicidad importe más que las funciones del broker
La mensajería de Redis es atractiva cuando Redis ya es parte de tu pila y la carga de trabajo es modesta. Evitas operar otro sistema distribuido. Los desarrolladores ya entienden los clientes de Redis, la monitorización, las credenciales y las rutas de implementación.
Esa es una razón válida. La simplicidad operativa tiene un valor real.
Redis también tiene una latencia muy baja. Si tu aplicación y Redis están en la misma región o red privada, publicar una pequeña notificación suele ser barato y rápido. Para la invalidación de caché o las actualizaciones de estado en vivo, un broker más pesado puede ser innecesario.
Redis también te permite combinar cambios de estado y mensajes con cuidado. Un script Lua o una transacción pueden actualizar una clave y añadir a un flujo en una sola operación del lado de Redis. Eso puede ser útil para sistemas pequeños donde Redis es el poseedor central del estado.
La trampa es que Redis no debería convertirse en tu broker accidental para todo. Si cada servicio comienza a añadir flujos de alto volumen sin un plan de retención, la elección "simple" se convierte en un almacén de registros en memoria sobrecargado.
Elige un broker dedicado cuando el manejo de fallos sea el producto
Kafka, RabbitMQ, Pulsar, NATS JetStream y los servicios de cola en la nube existen porque la mensajería se vuelve complicada rápidamente.
Usa un broker dedicado cuando necesites funciones como:
- Retención larga medida en semanas, meses o años.
- Historial de mensajes mucho más grande que la memoria.
- Colas de mensajes muertos y políticas de reintento integradas en el broker.
- Entrega retrasada, prioridades, claves de enrutamiento, intercambios o particionamiento de temas.
- Patrones de replicación entre regiones diseñados para mensajería.
- Muchos grupos de consumidores independientes reproduciendo el mismo historial de eventos.
- Herramientas más sólidas en torno al retraso, desplazamientos, reequilibrio y auditorías.
Kafka suele ser una mejor opción para canalizaciones de eventos de alto volumen y registros reproducibles. RabbitMQ suele ser una mejor opción para enrutamiento sofisticado, confirmaciones y colas de trabajo. Las colas en la nube suelen ser mejores cuando quieres durabilidad gestionada y límites operativos simples.
Redis Streams puede manejar cargas de trabajo de producción útiles, pero sigue siendo Redis. Sus datos están centrados en la memoria, su configuración de persistencia debe entenderse y sus funciones de broker son intencionalmente más pequeñas que las de los sistemas dedicados.
Una forma concreta de decidir
Haz estas preguntas antes de elegir Redis:
- ¿Puede un consumidor perder un mensaje sin pérdida de datos?
- ¿Necesita un consumidor desconectado ponerse al día?
- ¿Cuánto tiempo deben retenerse los mensajes?
- ¿Pueden los datos de mensajes retenidos caber cómodamente en la memoria de Redis?
- ¿Manejan los trabajadores los mensajes duplicados de forma segura?
- ¿Necesitas colas de mensajes muertos, reintentos retrasados, prioridades o reglas de enrutamiento?
- ¿Interferirá este tráfico con el almacenamiento en caché o las sesiones de Redis?
Si los mensajes perdidos son aceptables, Pub/Sub puede ser suficiente.
Si los consumidores necesitan ponerse al día y la retención es limitada, los Streams pueden ser suficientes.
Si los datos de los mensajes necesitan retención prolongada, reproducción por muchos equipos, comportamiento de broker complejo o una fuerte separación operativa, usa un broker dedicado.
Ejemplo: invalidación de caché
Una aplicación almacena páginas de productos en la memoria del proceso local y en Redis. Cuando un producto cambia, el servicio de administración publica:
PUBLISH cache:invalidate product:123
Cada instancia web suscrita a cache:invalidate elimina su copia local. Si una instancia web pierde el mensaje, su entrada local aún tiene un TTL de cinco minutos y también verifica un campo de versión del producto en la siguiente solicitud. Pub/Sub está bien porque hay una ruta de recuperación.
Usar Kafka aquí probablemente añadiría más peso operativo que valor.
Ejemplo: trabajos de correo electrónico en segundo plano
Un usuario se registra y necesitas enviar un correo electrónico de bienvenida. Si el trabajador está inactivo durante un minuto, el trabajo debe enviarse más tarde. Pub/Sub es una mala opción.
Un Redis Stream puede funcionar:
XADD email:jobs MAXLEN ~ 100000 * job_id abc123 type welcome user_id 42
Los trabajadores leen a través de un grupo de consumidores, envían el correo electrónico, registran job_id como completado y llaman a XACK. Un monitor verifica los trabajos pendientes y reclama los antiguos. Esto es razonable para una cola interna modesta.
Si la entrega de correo electrónico se vuelve a gran escala, necesita reintentos retrasados, manejo de mensajes muertos, límites de velocidad por cliente y paneles operativos completos, una cola dedicada comienza a verse mejor.
Ejemplo: eventos de auditoría
Los eventos de auditoría generalmente necesitan durabilidad, búsqueda, retención y, a veces, manejo legal o de cumplimiento. Redis Streams puede ayudar como un búfer corto, pero Redis no debería ser el almacén de auditoría final. Usa un registro duradero, base de datos, canalización de almacenamiento de objetos o servicio de eventos gestionado diseñado para retención y revisión.
Notas operativas si eliges Redis
Para Pub/Sub:
- Configura
client-output-buffer-limit pubsub. - Usa conexiones de suscriptor dedicadas.
- Construye comportamiento de reconexión y resuscripción.
- Trata los mensajes como pistas, no como hechos duraderos.
Para Streams:
- Establece una política de retención con
MAXLEN,MINIDo recorte explícito. - Monitorea las entradas pendientes.
- Haz que los consumidores sean idempotentes.
- Usa
XACKsolo después de que el trabajo tenga éxito. - Planifica cómo se reclaman y reintentan los mensajes estancados.
- Vigila la memoria, la persistencia y el retraso de replicación.
Redis es un buen broker de mensajes cuando eliges la parte de Redis que coincide con el trabajo. Pub/Sub es una señal en vivo. Los Streams son un registro duradero limitado. Ninguno debería elegirse solo porque Redis ya está en ejecución, pero ambos pueden ser la respuesta correcta más simple cuando su modelo de fallo coincide con tu aplicación.
El término medio incómodo
Muchos equipos aterrizan en el medio: Pub/Sub es demasiado propenso a pérdidas, Kafka parece demasiado grande y RabbitMQ parece un sistema más para operar. Redis Streams puede ser una buena respuesta allí, pero solo si lo tratas como una cola real y no como una lista mágica.
Un diseño saludable de Streams tiene propiedad sobre estos detalles:
- ¿Quién crea el flujo y el grupo de consumidores?
- ¿Cuántos consumidores se esperan?
- ¿Cuál es la antigüedad máxima pendiente antes de que se reclame un mensaje?
- ¿Qué sucede después de un fallo repetido?
- ¿Cuánto historial de flujo se retiene?
- ¿Qué panel o alerta muestra un retraso creciente?
Sin esas respuestas, los Streams pueden fallar silenciosamente. Un trabajador puede leer mensajes y fallar antes de XACK, dejando las entradas pendientes para siempre. Otro trabajador puede nunca reclamarlas. La longitud del flujo puede seguir creciendo porque nadie configuró el recorte. La memoria de Redis aumenta, pero el equipo de aplicación piensa "la cola es duradera", por lo que no se dan cuenta hasta que la instancia está bajo presión.
Un trabajador simple generalmente debería hacer este bucle:
leer un lote pequeño
procesar cada mensaje de forma idempotente
confirmar solo los mensajes exitosos
inspeccionar periódicamente los mensajes pendientes
reclamar mensajes pendientes estancados
recortar según la política de retención
Eso es más trabajo que Pub/Sub, y ese es el punto. La durabilidad siempre mueve la complejidad a algún lugar. Redis Streams mantiene el lado del broker bastante pequeño, pero la aplicación aún posee los reintentos, el comportamiento de mensajes muertos y la idempotencia.
Si nadie en el equipo quiere poseer esos detalles, una cola gestionada puede ser más barata a largo plazo, incluso si parece más pesada el primer día. El mejor broker no es el más rápido en un punto de referencia. Es aquel cuyo comportamiento de fallo tu equipo puede operar a las 3 a.m. sin adivinar.