tutoriales.com

Publicando y Suscribiendo Mensajes en Tiempo Real con Redis Pub/Sub

Descubre cómo aprovechar el mecanismo de Publicación y Suscripción (Pub/Sub) de Redis para construir arquitecturas orientadas a eventos y sistemas de chat en tiempo real rápidos y escalables utilizando Node.js.

Intermedio8 min de lectura2 views
Reportar error

Introducción al Patrón Pub/Sub en Redis 🚀

En el desarrollo de software moderno, la capacidad de comunicar diferentes componentes o servicios de forma instantánea es un requisito fundamental. Ya sea para notificaciones en vivo, chats, actualizaciones de paneles de control o procesamiento de eventos asíncronos, necesitamos herramientas que ofrezcan una latencia mínima.

Es aquí donde entra en juego el sistema de Publicación y Suscripción (conocido como Pub/Sub) de Redis. Este paradigma de mensajería desacopla al emisor de los mensajes (publisher) de los receptores (subscribers), permitiendo una comunicación fluida y en tiempo real sin que las partes necesiten conocerse entre sí.

📌 Nota: A diferencia de las estructuras de datos tradicionales de Redis (como strings, hashes o listas), los mensajes en Pub/Sub no se persisten en la memoria ni en disco. Si un suscriptor está desconectado cuando se publica un mensaje, ese mensaje se pierde para siempre.

¿Cómo Funciona Redis Pub/Sub? ⚙️

El funcionamiento del modelo Pub/Sub en Redis se basa en canales (channels). Un publicador envía un mensaje a un canal específico, y cualquier cliente que esté suscrito a ese mismo canal recibirá el mensaje de forma instantánea.

Publicador (Publisher) Canal 'notificaciones' Suscriptor 1 (Subscriber) Suscriptor 2 (Subscriber) Suscriptor 3 (Subscriber) Mensaje Distribución en tiempo real (Fan-out)

Características Principales

  • Desacoplamiento total: Los productores no saben quién consume sus mensajes y los consumidores no saben quién los produce.
  • Arquitectura de difusión (Broadcasting): Un único mensaje enviado a un canal puede ser recibido por cientos o miles de suscriptores al mismo tiempo.
  • Baja latencia: Al estar implementado en memoria sobre Redis, la entrega de mensajes ocurre en milisegundos.

Preparando el Entorno de Desarrollo 🛠️

Para poner en práctica este concepto, vamos a construir una pequeña aplicación utilizando Node.js y la librería oficial ioredis, que ofrece un soporte excelente para Pub/Sub.

Prerrequisitos

  • Tener instalado Node.js (versión 18 o superior).
  • Tener una instancia de Redis corriendo localmente o en la nube.

Inicializando el Proyecto

Crea una nueva carpeta para tu proyecto y ejecuta los siguientes comandos en tu terminal:

mkdir redis-pubsub-demo
cd redis-pubsub-demo
npm init -y
npm install ioredis

Intermedio Nivel técnico requerido para este tutorial.


Implementando el Servidor de Suscriptores 📥

El suscriptor es el componente encargado de escuchar uno o más canales a la espera de nuevos mensajes. Cuando llega un mensaje, la aplicación ejecuta un callback para procesarlo.

Crea un archivo llamado subscriber.js con el siguiente código:

const Redis = require("ioredis");

// Creamos una instancia dedicada para suscripciones
const subscriber = new Redis();

const CHANNEL_NAME = "chat-global";

async function iniciarSuscriptor() {
  try {
    await subscriber.subscribe(CHANNEL_NAME);
    console.log(`✅ Suscripto exitosamente al canal: ${CHANNEL_NAME}`);

    subscriber.on("message", (channel, message) => {
      console.log(`📩 Mensaje recibido en [${channel}]:`);
      
      try {
        const parsedMessage = JSON.parse(message);
        console.log(`De: ${parsedMessage.user} -> Texto: ${parsedMessage.text}`);
      } catch (e) {
        console.log(`Mensaje plano: ${message}`);
      }
    });
  } catch (error) {
    console.error("❌ Error al suscribirse:", error);
  }
}

iniciarSuscriptor();
💡 Consejo: Es una buena práctica en Redis utilizar conexiones dedicadas para las operaciones de suscripción, ya que un cliente suscrito entra en un modo especial donde solo puede aceptar comandos relacionados con Pub/Sub.

Implementando el Publicador de Mensajes 📤

El publicador es el encargado de enviar la información hacia el canal de Redis. No necesita estar suscrito a nada; su única responsabilidad es despachar el payload.

Crea un archivo llamado publisher.js:

const Redis = require("ioredis");

const publisher = new Redis();
const CHANNEL_NAME = "chat-global";

async function enviarMensaje(usuario, texto) {
  const payload = JSON.stringify({
    user: usuario,
    text: texto,
    timestamp: new Date().toISOString()
  });

  try {
    const receiversCount = await publisher.publish(CHANNEL_NAME, payload);
    console.log(`🚀 Mensaje enviado a ${receiversCount} cliente(s) conectado(s).`);
  } catch (error) {
    console.error("❌ Error al publicar el mensaje:", error);
  }
}

// Simulamos el envío de mensajes cada 3 segundos
let contador = 1;
setInterval(() => {
  enviarMensaje(`Usuario_${contador}`, `Hola a todos, este es el mensaje número ${contador}`);
  contador++;
}, 3000);

Probando el Sistema en Acción 🎬

Para ver la magia de Redis Pub/Sub funcionando, abre dos terminales diferentes en tu computadora:

  1. En la primera terminal, ejecuta el suscriptor:
node subscriber.js
  1. En la segunda terminal, ejecuta el publicador:
node publisher.js

Verás cómo el suscriptor comienza a recibir y procesar de manera instantánea cada uno de los mensajes generados por el publicador.

Publicador Node.js redis.publish() ENVÍA Motor Redis EN MEMORIA Procesamiento RAM DIFUNDE Suscriptor Node.js on('message') Entrega Instantánea (Latencia < 1ms) Tiempo

Patrones Avanzados: Uso de Wildcards con PSUBSCRIBE 🌟

Redis permite suscribirse a múltiples canales utilizando patrones con comodines (wildcards) mediante el comando PSUBSCRIBE.

Por ejemplo, si tienes canales para diferentes salas de chat como chat:es, chat:en o chat:fr, puedes suscribirte a todos ellos utilizando un patrón:

const Redis = require("ioredis");
const sub = new Redis();

async function iniciarSuscripcionPatron() {
  // El asterisco (*) actúa como comodín
  await sub.psubscribe("chat:*");
  console.log("👀 Escuchando todos los canales que empiezan con chat:");

  sub.on("pmessage", (pattern, channel, message) => {
    console.log(`Patrón coincidente: ${pattern}`);
    console.log(`Canal de origen: ${channel}`);
    console.log(`Mensaje: ${message}`);
  });
}

iniciarSuscripcionPatron();

Consideraciones y Buenas Prácticas ⚠️

Antes de llevar Redis Pub/Sub a un entorno de producción masivo, ten en cuenta las siguientes recomendaciones:

  • Pérdida de datos: Como se mencionó anteriormente, si no hay suscriptores activos, el mensaje se desecha. Si necesitas garantizar que los mensajes no se pierdan, considera utilizar Redis Streams en su lugar.
  • Memoria de salida (Output Buffers): Si un cliente suscriptor es muy lento procesando mensajes y el publicador envía información a gran velocidad, el búfer de salida de Redis puede crecer descontroladamente y consumir toda la memoria del servidor.
  • Escalabilidad horizontal: Cada mensaje publicado se duplica y se envía a cada cliente conectado. Si tienes millones de suscriptores, la red puede saturarse rápidamente.

Preguntas Frecuentes (FAQ) ❓

¿Puedo usar Redis Pub/Sub para persistir historiales de chat? No. Redis Pub/Sub no almacena ningún tipo de historial. Si un usuario entra tarde a una sala de chat, no verá los mensajes anteriores a menos que implementes una capa de almacenamiento adicional utilizando Redis Lists o una base de datos relacional/NoSQL.
¿Qué diferencia hay entre Redis Pub/Sub y Redis Streams? Pub/Sub es un sistema de mensajería efímero de tipo "fire-and-forget". Redis Streams, por otro lado, almacena los mensajes en un log con persistencia, permite consumidores concurrentes mediante grupos de consumidores y ofrece lectura retroactiva.

Conclusión 🎯

Has aprendido a implementar un sistema de mensajería en tiempo real altamente eficiente utilizando las capacidades Pub/Sub de Redis y Node.js. Este patrón es ideal para notificaciones ligeras, sistemas de anuncios y arquitecturas desacopladas donde la velocidad es más crítica que la persistencia a largo plazo.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!