devto 2026-09-30 원문 보기 ↗
Día 10 de la Serie de Arquitectura Open Source de Wisrovi.
Al construir arquitecturas distribuidas desacopladas, los equipos de ingeniería suelen enfrentarse a un dilema recurrente: Apache Kafka introduce una sobrecarga operativa considerable (JVM, ZooKeeper o KRaft, gestión de particiones en disco), mientras que el Pub/Sub clásico de Redis carece de persistencia (entrega at-most-once, pérdida de mensajes si un consumidor cae).
Redis Streams resuelve esta brecha al ofrecer estructuras de log inmutables en memoria con semántica de grupos de consumidores, confirmación de entrega explícita (XACK) y tolerancia a fallos nativa.
wredis proporciona un wrapper asíncrono robusto para producción que elimina el boilerplate y garantiza un procesamiento determinista de flujos de eventos.
| Dimensión | Redis Pub/Sub Clásico | Apache Kafka |
wredis Streams |
|---|---|---|---|
| Garantía de Entrega | A lo sumo una vez (fire-and-forget) | Al menos una vez / Exactamente una vez |
Al menos una vez (con XACK) |
| Offsets de Consumidor | Inexistente (instantáneo) | Persistidos en tópicos internos | Grupos de Consumidores (XREADGROUP) |
| Backlog de Mensajes | Se descarta si el consumidor cae | Persistido en disco | Persistido en Memoria (Capped Stream) |
| Sobrecarga de Infra | Mínima | Alta (cluster dedicado JVM) | Cero Infra Adicional (Reutiliza Redis existente) |
| Latencia de Procesamiento | Sub-milisegundo | Milisegundos de un dígito | Sub-milisegundo |
El siguiente ejemplo muestra cómo crear grupos de consumidores, publicar eventos a alta velocidad y confirmar lecturas de forma segura:
import asyncio
from wredis import RedisStreamClient
async def pipeline_eventos():
# Conexión al nodo soberano de Redis
cliente = RedisStreamClient(host="localhost", port=6379, db=0)
stream_key = "telemetria:sensores_iot"
grupo = "procesadores_analitica"
consumidor = "nodo_trabajador_01"
# Garantizar la existencia del Consumer Group sin excepciones si ya existe
await cliente.ensure_consumer_group(
stream=stream_key,
group=grupo,
create_stream_if_missing=True
)
# 1. Productor: Añadir evento con límite de memoria automático (MAXLEN)
id_evento = await cliente.add_event(
stream=stream_key,
fields={"sensor_id": "temp_42", "celsius": "28.4", "vibracion": "0.012"},
maxlen=100_000,
approximate=True
)
print(f"Evento publicado: {id_evento} en {stream_key}")
# 2. Consumidor: Lectura de mensajes asignados al grupo
mensajes = await cliente.read_group(
stream=stream_key,
group=grupo,
consumer=consumidor,
count=10,
block_ms=2000
)
for msg_id, datos in mensajes:
print(f"Procesando mensaje {msg_id}: {datos}")
# Lógica de negocio / agregación...
# 3. Confirmación atómica de procesamiento (XACK)
await cliente.ack_event(stream=stream_key, group=grupo, message_id=msg_id)
print(f"Mensaje {msg_id} confirmado exitosamente.")
await cliente.close()
if __name__ == "__main__":
asyncio.run(pipeline_eventos())
XCLAIM para reasignar automáticamente mensajes de trabajadores caídos hacia nodos saludables.MAXLEN ~): Evita el desbordamiento de RAM mediante poda aproximada de alta velocidad en el log.asyncio, endpoints en FastAPI y pipelines de wpipe.