--- title: "Cómo usar Redis Pub/Sub para mensajería en tiempo real" description: "Aprende a publicar y suscribirte a canales de Redis Pub/Sub con redis-cli y Python en Ubuntu 24.04, y cuándo conviene usar Redis Streams en su lugar." category: "Colas de Mensajes y Streaming" language: es source: https://cubepath.com/es/docs/colas-de-mensajes-y-streaming/redis-pub-sub-para-mensajeria-en-tiempo-real updated: 2026-09-25 --- # Cómo usar Redis Pub/Sub para mensajería en tiempo real Redis Pub/Sub es un sistema de mensajería publicar/suscribir integrado en Redis: los publicadores envían mensajes a un canal y Redis los entrega al instante a todos los clientes suscritos en ese momento. Es ideal para notificaciones en vivo, invalidación de cachés o actualizaciones de paneles cuando ya usas Redis. En esta guía instalarás Redis en Ubuntu 24.04, probarás Pub/Sub con `redis-cli`, escribirás un publicador y un suscriptor en Python y verás sus límites frente a Redis Streams. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Python 3 (incluido en Ubuntu 24.04). - Dos terminales abiertas en el servidor para ver publicador y suscriptor a la vez. ## Paso 1: Instalar Redis Ubuntu 24.04 incluye Redis 7 en sus repositorios oficiales, suficiente para todo lo que se ve en esta guía: ```bash sudo apt update sudo apt install redis-server ``` El paquete arranca y habilita el servicio automáticamente. Compruébalo: ```bash systemctl status redis-server --no-pager ``` ```output ● redis-server.service - Advanced key-value store Loaded: loaded (/usr/lib/systemd/system/redis-server.service; enabled; preset: enabled) Active: active (running) since Thu 2026-09-24 10:12:03 UTC; 8s ago ``` Y que responde: ```bash redis-cli ping ``` ```output PONG ``` ## Paso 2: Proteger Redis con contraseña Por defecto Redis en Ubuntu solo escucha en `127.0.0.1` y `::1`, así que no es accesible desde fuera. Aun así, conviene exigir contraseña para que cualquier proceso local no pueda leer ni publicar mensajes. Abre la configuración: ```bash sudo nano /etc/redis/redis.conf ``` Busca la línea `# requirepass foobared`, descoméntala y pon una contraseña robusta en lugar de **`your_strong_password`**. Comprueba también que `bind` sigue limitado a localhost: ```ini bind 127.0.0.1 -::1 requirepass your_strong_password ``` Reinicia Redis para aplicar el cambio: ```bash sudo systemctl restart redis-server ``` Para no escribir la contraseña en cada comando (ni dejarla en el historial con `-a`), `redis-cli` lee la variable de entorno `REDISCLI_AUTH`. Expórtala en cada terminal que uses: ```bash read -rs REDISCLI_AUTH && export REDISCLI_AUTH ``` Escribe la contraseña y pulsa `Enter` (no se muestra en pantalla). Verifica la autenticación: ```bash redis-cli ping ``` ```output PONG ``` Si ves `NOAUTH Authentication required.`, la variable no está definida en esa terminal. ## Paso 3: Publicar y suscribirse con redis-cli Un canal de Pub/Sub no se crea ni se declara: existe mientras alguien está suscrito. En la **primera terminal**, suscríbete al canal `notificaciones`: ```bash redis-cli SUBSCRIBE notificaciones ``` ```output Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "notificaciones" 3) (integer) 1 ``` La conexión queda bloqueada esperando mensajes. En la **segunda terminal** (con `REDISCLI_AUTH` exportada), publica un mensaje: ```bash redis-cli PUBLISH notificaciones "Mantenimiento programado a las 02:00" ``` ```output (integer) 1 ``` El número que devuelve `PUBLISH` es cuántos clientes recibieron el mensaje. En la primera terminal aparece al momento: ```output 1) "message" 2) "notificaciones" 3) "Mantenimiento programado a las 02:00" ``` Ahora detén el suscriptor con `Ctrl+C` y vuelve a publicar: ```bash redis-cli PUBLISH notificaciones "Nadie escucha" ``` ```output (integer) 0 ``` Ese mensaje se ha perdido: Redis no guarda nada para suscriptores futuros. Esta es la característica más importante de Pub/Sub y la razón para elegir Streams en ciertos casos (Paso 6). ## Paso 4: Suscribirse a patrones con PSUBSCRIBE Con `PSUBSCRIBE` un cliente recibe los mensajes de todos los canales que coinciden con un patrón de tipo glob (`*`, `?`, `[abc]`). Es útil cuando el nombre del canal incluye un identificador, como `usuario::eventos`. En la primera terminal: ```bash redis-cli PSUBSCRIBE 'usuario:*:eventos' ``` En la segunda, publica en dos canales distintos: ```bash redis-cli PUBLISH usuario:42:eventos "login" redis-cli PUBLISH usuario:77:eventos "cambio de contraseña" ``` El suscriptor recibe ambos como `pmessage`, con el patrón y el canal concreto: ```output 1) "pmessage" 2) "usuario:*:eventos" 3) "usuario:42:eventos" 4) "login" 1) "pmessage" 2) "usuario:*:eventos" 3) "usuario:77:eventos" 4) "cambio de contraseña" ``` Con el suscriptor todavía activo, consulta desde la segunda terminal qué canales y patrones hay en uso con el comando `PUBSUB`: ```bash redis-cli PUBSUB CHANNELS redis-cli PUBSUB NUMPAT ``` ```output (empty array) (integer) 1 ``` `PUBSUB CHANNELS` solo lista canales con suscripciones directas (`SUBSCRIBE`), no los cubiertos por patrones; por eso sale vacío. `PUBSUB NUMSUB canal` devuelve el número de suscriptores directos de un canal concreto. > Nota: En Redis Cluster, `PUBLISH` se reenvía a todos los nodos. Desde Redis 7 existen `SPUBLISH` y `SSUBSCRIBE` (Pub/Sub fragmentado), que solo envían el mensaje al fragmento propietario del canal y escalan mejor en clústeres grandes. En una instancia única no hay diferencia. ## Paso 5: Publicador y suscriptor en Python En una aplicación real usarás una biblioteca cliente. Ubuntu 24.04 no permite instalar paquetes con `pip` a nivel de sistema, así que crea un entorno virtual para el proyecto: ```bash sudo apt install python3-venv mkdir -p ~/redis-pubsub && cd ~/redis-pubsub python3 -m venv venv ./venv/bin/pip install redis ``` Los scripts leen la contraseña de la variable `REDIS_PASSWORD` en lugar de llevarla escrita en el código. Expórtala en ambas terminales: ```bash export REDIS_PASSWORD="$REDISCLI_AUTH" ``` ### El suscriptor Crea `suscriptor.py`: ```bash nano ~/redis-pubsub/suscriptor.py ``` ```python import json import os import redis r = redis.Redis( host="127.0.0.1", port=6379, password=os.environ.get("REDIS_PASSWORD"), decode_responses=True, ) # ignore_subscribe_messages oculta las confirmaciones de suscripción pubsub = r.pubsub(ignore_subscribe_messages=True) pubsub.subscribe("notificaciones") pubsub.psubscribe("usuario:*:eventos") print("Esperando mensajes (Ctrl+C para salir)...") try: for message in pubsub.listen(): try: data = json.loads(message["data"]) except (TypeError, json.JSONDecodeError): data = message["data"] print(f"[{message['channel']}] {data}") except KeyboardInterrupt: pass finally: pubsub.close() ``` `listen()` es un generador bloqueante: espera en el socket sin consumir CPU y devuelve un diccionario por mensaje con las claves `type`, `pattern`, `channel` y `data`. ### El publicador Crea `publicador.py`: ```bash nano ~/redis-pubsub/publicador.py ``` ```python import json import os import sys from datetime import datetime, timezone import redis r = redis.Redis( host="127.0.0.1", port=6379, password=os.environ.get("REDIS_PASSWORD"), decode_responses=True, ) def publicar_evento(user_id: int, evento: str) -> int: canal = f"usuario:{user_id}:eventos" payload = { "evento": evento, "fecha": datetime.now(timezone.utc).isoformat(), } return r.publish(canal, json.dumps(payload)) if __name__ == "__main__": user_id = int(sys.argv[1]) if len(sys.argv) > 1 else 42 receptores = publicar_evento(user_id, "login") print(f"Mensaje entregado a {receptores} suscriptor(es)") ``` ### Probarlo En la primera terminal, arranca el suscriptor: ```bash cd ~/redis-pubsub ./venv/bin/python suscriptor.py ``` En la segunda, publica un evento: ```bash cd ~/redis-pubsub ./venv/bin/python publicador.py 42 ``` ```output Mensaje entregado a 1 suscriptor(es) ``` El suscriptor lo muestra ya decodificado: ```output Esperando mensajes (Ctrl+C para salir)... [usuario:42:eventos] {'evento': 'login', 'fecha': '2026-09-24T10:31:07.482113+00:00'} ``` Si ejecutas el publicador sin el suscriptor en marcha, el resultado será `0` y el mensaje se descarta. ## Paso 6: Pub/Sub frente a Redis Streams Pub/Sub entrega cada mensaje como máximo una vez y solo a los clientes conectados en ese instante. Si tu suscriptor se reinicia o pierde la conexión, pierde los mensajes publicados mientras tanto. Redis Streams, en cambio, guarda los mensajes y permite releerlos o repartirlos entre varios consumidores con confirmación (`XACK`). | Característica | Pub/Sub | Streams | |---|---|---| | Persistencia | No, se descarta al entregar | Sí, queda en el stream | | Suscriptor desconectado | Pierde los mensajes | Los lee al volver | | Confirmación de entrega | No | Sí, con grupos de consumidores | | Reparto de carga entre workers | No, todos reciben todo | Sí, con `XREADGROUP` | | Latencia | Mínima | Muy baja | | Uso típico | Notificaciones en vivo, invalidar cachés, chat | Colas de trabajo, eventos que no se pueden perder | Para ver la diferencia, añade una entrada a un stream sin que nadie la esté leyendo: ```bash redis-cli XADD eventos '*' tipo login user_id 42 ``` ```output "1790243467123-0" ``` Y léela después desde el principio (`0`): ```bash redis-cli XREAD COUNT 10 STREAMS eventos 0 ``` ```output 1) 1) "eventos" 2) 1) 1) "1790243467123-0" 2) 1) "tipo" 2) "login" 3) "user_id" 4) "42" ``` El mensaje seguía ahí aunque no hubiese consumidores cuando se escribió. Si no puedes permitirte perder eventos, usa Streams con grupos de consumidores (o un broker como RabbitMQ) en lugar de intentar añadir fiabilidad encima de Pub/Sub. ## Solución de problemas ### El suscriptor se desconecta con mensajes grandes o mucho volumen Redis acumula en memoria los mensajes pendientes de enviar a cada suscriptor. Si un cliente lee más despacio de lo que se publica, Redis lo desconecta al superar `client-output-buffer-limit` para la clase `pubsub` (por defecto 32 MB de límite duro, o 8 MB mantenidos durante 60 segundos). Consulta el valor actual: ```bash redis-cli CONFIG GET client-output-buffer-limit ``` La solución habitual es que el suscriptor procese más rápido (por ejemplo, delegando el trabajo pesado a otra cola) en lugar de subir el límite sin más. ### NOAUTH Authentication required El cliente no envía contraseña. En `redis-cli`, exporta `REDISCLI_AUTH`; en Python, comprueba que `REDIS_PASSWORD` está definida en la terminal donde ejecutas el script. ### El suscriptor no recibe nada Comprueba que publicador y suscriptor usan exactamente el mismo nombre de canal (distingue mayúsculas) y que el patrón de `PSUBSCRIBE` va entre comillas simples en la shell, para que Bash no expanda el `*`. Mientras el suscriptor está activo, `redis-cli PUBSUB NUMSUB notificaciones` debe devolver al menos `1`. ## Conclusión Has instalado y protegido Redis en Ubuntu 24.04, probado `SUBSCRIBE`, `PSUBSCRIBE` y `PUBLISH` desde `redis-cli`, y construido un publicador y un suscriptor en Python. Pub/Sub es la opción más sencilla y rápida para mensajes efímeros en tiempo real; para eventos que no pueden perderse, Redis Streams es la herramienta adecuada. Como siguientes pasos, puedes ejecutar el suscriptor como servicio de systemd, conectar Pub/Sub a un servidor WebSocket para enviar notificaciones al navegador, o explorar los grupos de consumidores de Redis Streams.