Casos de uso de Redis: Caché, Colas y Limitación de Tasa

Backend2026-10-06TryQuickToolBox

Has construido una aplicación web que funciona bien con pocos usuarios, pero a medida que crece el tráfico, notas cargas de página lentas, trabajos en segundo plano duplicados y APIs bombardeadas por clientes abusivos. Estos son problemas clásicos de escalabilidad que Redis puede resolver elegantemente. Redis es un almacén de datos en memoria que sobresale en tres tareas principales: caché, colas y limitación de tasa. En este artículo, exploraremos cada caso de uso con ejemplos prácticos y mejores prácticas.

¿Por qué Redis para estos casos de uso?

Redis almacena datos en memoria, lo que lo hace increíblemente rápido, a menudo con tiempos de respuesta inferiores a un milisegundo. Admite estructuras de datos ricas como cadenas, listas, conjuntos, conjuntos ordenados y hashes, que se asignan naturalmente a caché, colas y limitación de tasa. También ofrece operaciones atómicas, pub/sub y opciones de persistencia, lo que lo convierte en una herramienta versátil para desarrolladores backend.

1. Caché con Redis

El caché es el caso de uso más común de Redis. Al almacenar datos de acceso frecuente en Redis, reduces la carga de la base de datos y aceleras las respuestas.

Cómo funciona el caché

Cuando llega una solicitud, verifica si los datos existen en Redis. Si es así (acierto de caché), devuélvelos directamente. Si no (fallo de caché), obténlos de la base de datos, guárdalos en Redis con un tiempo de expiración y devuélvelos. Este patrón se llama cache-aside.

// Ejemplo en Node.js usando ioredis
const Redis = require('ioredis');
const redis = new Redis();

async function getUser(userId) {
  const cacheKey = `user:${userId}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
  await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600); // TTL de 1 hora
  return user;
}

Mejores prácticas para el caché

Estrategias de invalidación de caché

La invalidación es difícil. Las estrategias comunes incluyen:

2. Colas con Redis

Las colas desacoplan tareas que consumen tiempo del ciclo de solicitud-respuesta. Por ejemplo, enviar correos electrónicos, procesar imágenes o generar informes se puede hacer de forma asíncrona.

Implementando una cola simple

Las listas de Redis son perfectas para colas. Usa LPUSH para agregar trabajos a la izquierda y BRPOP para bloquear y extraer de la derecha (FIFO).

// Productor: agregar trabajo
await redis.lpush('email_queue', JSON.stringify({ to: 'user@example.com', subject: 'Welcome' }));

// Consumidor: procesar trabajo (en un worker)
while (true) {
  const job = await redis.brpop('email_queue', 0); // 0 = bloquear indefinidamente
  const { to, subject } = JSON.parse(job[1]);
  await sendEmail(to, subject);
}

Colas confiables con BRPOPLPUSH

Para evitar perder trabajos si un worker falla, usa BRPOPLPUSH para mover atómicamente el trabajo a una lista de procesamiento. Después de un procesamiento exitoso, elimínalo de la lista de procesamiento. Si el worker muere, otro worker puede recuperar trabajos de la lista de procesamiento.

const job = await redis.brpoplpush('email_queue', 'processing_queue', 0);
try {
  // procesar trabajo
  await redis.lrem('processing_queue', 1, job);
} catch (err) {
  // manejar error, quizás reencolar
}

Bibliotecas de colas dedicadas

Para producción, considera bibliotecas como Bull (Node.js), RQ (Python) o Sidekiq (Ruby). Proporcionan reintentos, programación y monitoreo listos para usar.

3. Limitación de tasa con Redis

La limitación de tasa protege tu API del abuso y asegura un uso justo. Las operaciones atómicas de Redis lo hacen ideal para contar solicitudes.

Limitación de tasa de ventana fija

Incrementa un contador para cada usuario por ventana de tiempo. Si el conteo excede el límite, rechaza la solicitud.

async function isAllowed(userId, limit = 100, windowSec = 60) {
  const key = `rate:${userId}:${Math.floor(Date.now() / 1000 / windowSec)}`;
  const count = await redis.incr(key);
  if (count === 1) await redis.expire(key, windowSec);
  return count