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:

sudo apt update
sudo apt install redis-server

El paquete arranca y habilita el servicio automáticamente. Compruébalo:

systemctl status redis-server --no-pager
● 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:

redis-cli ping
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:

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:

bind 127.0.0.1 -::1
requirepass your_strong_password

Reinicia Redis para aplicar el cambio:

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:

read -rs REDISCLI_AUTH && export REDISCLI_AUTH

Escribe la contraseña y pulsa Enter (no se muestra en pantalla). Verifica la autenticación:

redis-cli ping
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:

redis-cli SUBSCRIBE notificaciones
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:

redis-cli PUBLISH notificaciones "Mantenimiento programado a las 02:00"
(integer) 1

El número que devuelve PUBLISH es cuántos clientes recibieron el mensaje. En la primera terminal aparece al momento:

1) "message"
2) "notificaciones"
3) "Mantenimiento programado a las 02:00"

Ahora detén el suscriptor con Ctrl+C y vuelve a publicar:

redis-cli PUBLISH notificaciones "Nadie escucha"
(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:<id>:eventos. En la primera terminal:

redis-cli PSUBSCRIBE 'usuario:*:eventos'

En la segunda, publica en dos canales distintos:

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:

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:

redis-cli PUBSUB CHANNELS
redis-cli PUBSUB NUMPAT
(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.

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:

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:

export REDIS_PASSWORD="$REDISCLI_AUTH"

El suscriptor

Crea suscriptor.py:

nano ~/redis-pubsub/suscriptor.py
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:

nano ~/redis-pubsub/publicador.py
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:

cd ~/redis-pubsub
./venv/bin/python suscriptor.py

En la segunda, publica un evento:

cd ~/redis-pubsub
./venv/bin/python publicador.py 42
Mensaje entregado a 1 suscriptor(es)

El suscriptor lo muestra ya decodificado:

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ísticaPub/SubStreams
PersistenciaNo, se descarta al entregarSí, queda en el stream
Suscriptor desconectadoPierde los mensajesLos lee al volver
Confirmación de entregaNoSí, con grupos de consumidores
Reparto de carga entre workersNo, todos reciben todoSí, con XREADGROUP
LatenciaMínimaMuy baja
Uso típicoNotificaciones en vivo, invalidar cachés, chatColas 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:

redis-cli XADD eventos '*' tipo login user_id 42
"1790243467123-0"

Y léela después desde el principio (0):

redis-cli XREAD COUNT 10 STREAMS eventos 0
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:

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.