Caché Redis en 2026: Redis vs Memcached vs CDN
Equipo Arvucore
September 22, 2025 · Actualizado el August 26, 2026
15 min read
Usa cache-aside con TTL más invalidación explícita como opción por defecto, pon una CDN delante de todo lo que sea público y cacheable, y elige Redis antes que Memcached salvo que tu única necesidad sea get/set de valores pequeños con concurrencia muy alta. Todo lo demás se reduce a dos problemas: mantener los datos suficientemente frescos y asegurarte de que un cache miss no tumbe la base de datos.
Las cuatro capas de caché y para qué sirve cada una
Una petición puede responderse en cuatro puntos, cada uno con su propio dueño, horizonte de TTL y mecanismo de invalidación.
| Capa | Dónde vive | TTL típico | Invalidación | Ideal para |
|---|---|---|---|---|
| Navegador / HTTP | Dispositivo del usuario | De minutos a un año | URLs versionadas, Cache-Control, ETag |
Assets estáticos, fuentes, bundles inmutables |
| CDN / edge | PoPs del proveedor cerca del usuario | De segundos a días | API de purga, surrogate keys, s-maxage |
Páginas públicas, imágenes, respuestas de API cacheables |
| Aplicación | Redis, Memcached o memoria del proceso | De segundos a horas | TTL, invalidación en escritura, claves versionadas | Fragmentos renderizados, sesiones, objetos calculados, rate limits |
| Base de datos / consulta | Buffer pool de la BD, vistas materializadas, caché de consultas | Gestionado por la BD | Automática o refresco programado | Filas calientes, agregaciones costosas |
Diseña de fuera hacia dentro: empuja a la CDN todo lo que pueda ser público, mantén los datos por usuario o de cambio rápido en la caché de aplicación y deja que la caché de la base de datos se encargue del resto. La memoria del proceso (un Map en Node, Caffeine en la JVM) es una quinta capa: la más rápida con diferencia, pero por instancia y desaparece en cada deploy. Úsala para configuración, feature flags y objetos pequeños muy calientes delante de Redis.
Patrones de caché: cache-aside, read-through, write-through, write-behind, refresh-ahead
El patrón decide quién puebla la caché y cuándo le llegan las escrituras.
Cache-aside (lazy loading). La aplicación consulta la caché, lee la base de datos en caso de miss, escribe el valor de vuelta y lo devuelve. Tolera una caída de la caché, funciona con cualquier store y solo cachea lo que se lee. El coste: cada miss paga la consulta completa, y cada escritor tiene que acordarse de invalidar.
Read-through. Mismo comportamiento de lectura, pero es la librería de caché o el proxy quien carga desde la base de datos en el miss. Puntos de llamada más limpios, menos flexibilidad.
Write-through. Las escrituras van a la caché, que escribe de forma síncrona en la base de datos. Nunca queda desactualizada para los datos escritos a través de ella, a cambio de latencia de escritura y de cachear datos que nadie lee.
Write-behind (write-back). Las escrituras van a la caché y se vuelcan de forma asíncrona, por lotes. Alto rendimiento de escritura, pero si el nodo de caché muere antes del volcado, las escrituras se pierden. Solo para datos que puedes permitirte perder (contadores, estadísticas de visualización, presencia).
Refresh-ahead. La caché renueva una clave caliente en segundo plano antes de que expire. Bueno para unas pocas claves costosas y predecibles; un desperdicio en una cola larga.
| Patrón | Coste del miss en lectura | Latencia de escritura | Desactualización | Riesgo de pérdida de datos | Por defecto para |
|---|---|---|---|---|---|
| Cache-aside | Consulta a BD + escritura en caché | Ninguna | Hasta el TTL o la invalidación | Ninguno | La mayoría de cargas con muchas lecturas |
| Read-through | Lo mismo, dentro de la capa de caché | Ninguna | Hasta el TTL o la invalidación | Ninguno | Equipos que estandarizan en una librería |
| Write-through | Bajo (el dato suele estar presente) | Caché + BD, síncrono | Mínima | Ninguno | Consistencia read-after-write |
| Write-behind | Bajo | Solo caché | Mínima para lecturas | Sí, hasta el volcado | Contadores, telemetría, altas tasas de escritura |
| Refresh-ahead | Casi cero para claves calientes | Ninguna | Acotada por el intervalo de refresco | Ninguno | Pocas claves costosas y predecibles |
Si tienes dudas, empieza con cache-aside detrás de una interfaz de repositorio, como en la arquitectura hexagonal; después podrás mover claves individuales a write-through o refresh-ahead sin tocar a quien las llama.
Estrategia de invalidación y TTL
TTL e invalidación no son alternativas. El TTL acota cuánto pueden envejecer los datos cuando la invalidación falla; la invalidación mantiene los datos frescos cuando funciona. Usa ambos.
Elige TTLs por clase de dato, no por servicio. Un catálogo que cambia unas pocas veces al día puede vivir una hora; un nivel de stock en el checkout, unos segundos, si acaso. Documenta las clases; son el contrato contra el que implementa el equipo.
Invalida en la escritura, en el origen. La ruta de código que actualiza la base de datos borra la clave de caché o emite un evento que lo hace. Borrar es más seguro que actualizar: una actualización puede competir con una lectura concurrente que escriba de vuelta un valor más antiguo.
Versiona claves en lugar de purgar un namespace. Pon una versión en la clave (catalog:v42:product:123) e increméntala en las actualizaciones masivas. Las entradas antiguas quedan inalcanzables y expiran solas.
Añade jitter. Las claves calentadas juntas con el mismo TTL expiran juntas. Aleatoriza cada TTL entre un 10 y un 20 por ciento.
Usa eventos para la invalidación entre servicios. En una arquitectura basada en eventos, el servicio dueño de una tabla publica ProductUpdated; los consumidores que cachean datos de producto se suscriben y descartan sus claves. El pub/sub o las keyspace notifications de Redis sirven para un único despliegue de Redis; un message broker es la herramienta adecuada en cuanto intervienen varios servicios.
Protección contra stampede: lock, expiración anticipada, coalescencia de peticiones
La caída clásica de caché no es que la caché se caiga. Es que una clave popular expire bajo carga: cientos de peticiones fallan a la vez, todas ejecutan la misma consulta costosa y la base de datos se viene abajo. Estas técnicas se combinan.
Lock por clave. En el miss, la primera petición toma un lock corto (SET lock:key 1 NX PX 5000), reconstruye, escribe y libera. Las demás esperan un momento y vuelven a leer, o sirven una copia desactualizada. El TTL del lock debe superar una reconstrucción normal.
Coalescencia de peticiones (single-flight). Dentro de un proceso, deduplica las cargas concurrentes de la misma clave para que solo haya una llamada a la base de datos en vuelo. El singleflight de Go es la referencia; en Node es un map de promesas pendientes.
Expiración anticipada probabilística. Cada lectura decide, con una probabilidad que crece a medida que se acerca la expiración, renovar antes de tiempo. Las claves calientes las renueva un lector antes de que expiren; las frías se dejan en paz. Sin scheduler.
Sirve el valor antiguo mientras reconstruyes. Mantén el TTL lógico más corto que el TTL físico. En ese intervalo, los lectores reciben el valor antiguo de inmediato mientras uno de ellos reconstruye.
Aquí tienes cache-aside con lock y coalescencia en el proceso en TypeScript, usando el cliente ioredis:
import Redis from "ioredis";
const redis = new Redis();
const inflight = new Map<string, Promise<string>>();
export async function cached(
key: string,
ttlSec: number,
load: () => Promise<string>,
): Promise<string> {
const hit = await redis.get(key);
if (hit !== null) return hit;
// Agrupa los misses concurrentes dentro de este proceso.
const pending = inflight.get(key);
if (pending) return pending;
const task = (async () => {
const lockKey = `lock:${key}`;
const gotLock = await redis.set(lockKey, "1", "PX", 5000, "NX");
if (!gotLock) {
// Otra instancia está reconstruyendo; espera un momento y vuelve a comprobar.
await new Promise((r) => setTimeout(r, 50));
const again = await redis.get(key);
if (again !== null) return again;
// Sigue adelante y carga de todos modos, en lugar de bloquear para siempre.
}
try {
const value = await load();
const jitter = Math.floor(ttlSec * (0.9 + Math.random() * 0.2));
await redis.set(key, value, "EX", jitter);
return value;
} finally {
if (gotLock) await redis.del(lockKey);
}
})();
inflight.set(key, task);
try {
return await task;
} finally {
inflight.delete(key);
}
}
El fallthrough tras un lock fallido es deliberado: bloquear a todos los que esperan convierte una reconstrucción lenta en una caída, mientras que dejar que unos pocos carguen en paralelo acota el daño.
Los trade-offs de consistencia que realmente estás asumiendo
Una caché es una réplica con un modelo de consistencia más débil que el de la base de datos. Sé explícito sobre qué modelo recibe cada clase de dato.
- Eventual con cota. Cache-aside más TTL. Los lectores pueden ver datos de hasta TTL segundos de antigüedad. Vale para catálogos, contenido, resultados de búsqueda y la mayoría de dashboards.
- Read-your-writes. Después de que un usuario actualice algo, tiene que verlo. Borra la clave en la escritura y salta la caché en la siguiente lectura de ese usuario, o usa write-through para esa clave. Las sesiones y las ediciones de perfil lo necesitan.
- Lecturas monotónicas. Un usuario nunca debe ver los datos retroceder. Se rompe cuando dos instancias guardan versiones distintas en caché. Arréglalo con claves versionadas o enrutando al usuario siempre a la misma réplica.
- Fuerte. No cachees. Los descuentos de inventario, los saldos y el estado de los pagos van a la base de datos.
El bug de producción más común es un desajuste: consistencia eventual aplicada a un campo que el producto trata como fuerte. Clasifica primero; elige el patrón después.
Redis vs Memcached: tabla comparativa
| Criterio | Redis | Memcached |
|---|---|---|
| Estructuras de datos | Strings, hashes, listas, sets, sorted sets, streams, bitmaps, HyperLogLog, geoespacial, módulos de JSON y búsqueda | Solo strings (valores de bytes opacos) |
| Persistencia | Opcional: snapshots RDB, log AOF o ambos | Ninguna; reiniciar significa caché vacía |
| Replicación y HA | Primario-réplica, Sentinel para failover, Redis Cluster para sharding con failover | Nada integrado; los clientes hacen sharding con consistent hashing |
| Clúster | Nativo (Redis Cluster, hash slots, resharding) | Solo en el cliente o en el proxy |
| Eficiencia de memoria | Mayor overhead por clave; los hashes y sets pequeños se codifican de forma compacta | Slab allocator, overhead muy bajo por clave; puede desperdiciar memoria entre clases de slab |
| Hilos | Ejecución de comandos en un solo hilo con hilos de I/O; escala por sharding | Totalmente multihilo; un nodo grande escala con los cores |
| Operaciones atómicas | Ricas: INCR, SETNX, MULTI/EXEC, scripts Lua, Functions | INCR/DECR, CAS, add/replace |
| Eviction | Configurable: LRU, LFU, por TTL, solo volátiles o todas las claves | LRU por clase de slab |
| Pub/sub y streams | Sí | No |
| Tamaño máximo de valor | 512 MB | 1 MB por defecto (configurable) |
| Superficie operativa | Mayor: ajuste de persistencia, lag de replicación, topología del clúster | Mínima: memoria y conexiones |
| Nota sobre licencia | Comprueba la licencia de la distribución concreta; Redis, Valkey (fork de la Linux Foundation) y las variantes gestionadas en la nube difieren | Open source, BSD |
| Casos de uso típicos | Sesiones, rate limiting, rankings, colas, locks, feature flags, objetos calculados, contadores en tiempo real | Caché de objetos pura para fragmentos renderizados, resultados de ORM, respuestas de API |
Elige Memcached para una caché de objetos grande, plana y multihilo, con valores simples por debajo de 1 MB, donde perderlo todo en un reinicio sea aceptable. Su simplicidad es la ventaja.
Elige Redis cuando necesites cualquier estructura de datos, operaciones atómicas, locks, pub/sub, persistencia o replicación integrada. Eso describe a la mayoría de cachés de aplicación una vez que pasan del get/set, y por eso Redis (o Valkey, su fork comunitario) es hoy la opción por defecto. Si ya usas Redis para sesiones o colas, un segundo sistema solo para caché rara vez compensa. Todas las grandes nubes ofrecen ambos como servicio gestionado; comprueba el retraso de versiones, el comportamiento del failover y el precio por nodo antes de comprometerte con funciones como Cluster.
Caché en CDN: Cache-Control, stale-while-revalidate y surrogate keys
La CDN es la capa más barata por petición y la más fácil de configurar mal, porque las reglas viven en cabeceras HTTP que la mayoría del código de aplicación nunca define a propósito.
Cache-Control es el contrato. Separa los tiempos de vida del navegador y del edge:
Cache-Control: public, max-age=60, s-maxage=3600, stale-while-revalidate=300, stale-if-error=86400
max-age gobierna el navegador, s-maxage gobierna las cachés compartidas (la CDN), stale-while-revalidate permite que el edge sirva una copia expirada mientras vuelve a pedirla en segundo plano, y stale-if-error le permite seguir sirviendo si el origen devuelve 5xx. Para respuestas por usuario, define private o no-store; una cabecera Set-Cookie en una respuesta cacheable es la forma clásica de filtrar la página de un usuario a otro.
Los assets inmutables reciben vidas largas. Añade un fingerprint al nombre del archivo en tiempo de build (app.3f9a1c.js) y envía Cache-Control: public, max-age=31536000, immutable. Invalida cambiando la URL, nunca purgando; todo bundler moderno lo hace por defecto.
Las surrogate keys hacen la purga precisa. Etiqueta cada respuesta con las entidades de las que depende (Surrogate-Key: product-123 category-9, o el Cache-Tag del proveedor). Cuando el producto 123 cambia, purga esa etiqueta y toda página que lo haya renderizado sale del edge en una sola llamada. Conéctalo al mismo evento de escritura que limpia Redis: un evento, dos purgas. Prefiere una purga suave (marcar como obsoleto, servir lo obsoleto, volver a pedir) para que una actualización masiva no envíe un muro de misses al origen.
Origin shielding. Activa el shield o la caché por niveles del proveedor para que todos los PoPs pidan a una única caché regional; la mayoría de CDNs también agrupan los misses concurrentes de la misma URL.
Para sitios estáticos y con mucho contenido, un build Jamstack lleva la decisión de caché hasta el momento del deploy, y la CDN se convierte en el origen.
Observabilidad: tasa de aciertos, p99 y las métricas que predicen caídas
Una caché sin métricas es una suposición. Instrumenta estas desde el primer día.
- Tasa de aciertos por clase de clave, no solo global. Una tasa global alta puede esconder una tasa pobre justo en la consulta que importa.
- Latencia p99 del origen y carga de la base de datos junto a la tasa de aciertos. Si el p99 se dispara cada vez que la tasa baja unos puntos, tienes riesgo de stampede.
- Evictions por segundo y fragmentación de memoria. Evictions al alza con tráfico estable significan que la caché es demasiado pequeña o los TTL demasiado largos (
INFO memoryeINFO statsen Redis;stats slabsen Memcached). - Tiempo de reconstrucción de las claves más costosas. Define el TTL del lock y la ventana de datos obsoletos.
- Lag de replicación, si las lecturas van a réplicas de Redis.
- Tasa de aciertos de la CDN por ruta y estado, más la latencia de purga.
Alerta sobre tendencias y no sobre umbrales: una caída de la tasa de aciertos a lo largo de diez minutos, o un p99 por encima del SLO durante una ventana sostenida. Envíalo al mismo pipeline de manejo de errores y logging que el resto de la plataforma.
Checklist de decisión
Repasa esta lista antes de añadir o cambiar una caché.
- ¿Cuál es el coste de un miss? Si es una consulta indexada y barata, quizá aún no necesites la caché. Mide primero.
- ¿Qué consistencia exige este dato? Eventual, read-your-writes, monotónica o fuerte. Fuerte significa sin caché.
- ¿Qué capa responde más barato? Público e idéntico para todos: CDN. Por usuario o de cambio rápido: caché de aplicación. Asset inmutable: navegador con URL con fingerprint.
- ¿Qué patrón? Cache-aside por defecto. Write-through para read-after-write. Write-behind solo para datos que toleran pérdida. Refresh-ahead para unas pocas claves calientes y costosas.
- ¿Cuál es el TTL y qué lo invalida antes? Documenta ambos. Añade jitter.
- ¿Qué pasa cuando la clave expira bajo carga? Lock, coalescencia, servir el valor antiguo o expiración anticipada; al menos una para cada clave cuya reconstrucción sea más lenta que una consulta simple.
- ¿Redis o Memcached? Cualquier cosa más allá de get/set, o persistencia o HA: Redis (o Valkey). Caché de objetos plana, máxima simplicidad: Memcached.
- ¿Cómo sabrás que funciona? Tasa de aciertos por clase, p99 del origen, evictions, tiempo de reconstrucción, latencia de purga, todo antes del rollout.
- ¿Cómo falla la caché? El cache-aside debe degradar a la base de datos detrás de un circuit breaker, para que una caída de Redis sea lentitud y no indisponibilidad. Pruébalo.
- ¿Quién es dueño de la invalidación cuando un segundo servicio escribe en la misma tabla? Si la respuesta es "nadie", usa eventos.
Recomendación
Empieza con cache-aside sobre Redis (o Valkey), TTLs por clase de dato con jitter, invalidación por borrado en la escritura y un lock por clave con coalescencia en el proceso para toda clave cuya reconstrucción sea costosa. Pon una CDN delante de cada respuesta pública con Cache-Control explícito, stale-while-revalidate y surrogate keys conectadas a los mismos eventos de invalidación. Reserva Memcached para la caché de objetos plana y multihilo donde la simplicidad es el objetivo. Instrumenta la tasa de aciertos por clase de clave frente al p99 del origen antes de publicar; ese par te dice si la caché es una comodidad o un muro de carga. En Arvucore solemos recomendar clasificar los datos por requisito de consistencia primero y elegir stores y patrones después; los equipos que lo hacen al revés acaban depurando datos obsoletos en producción.
¿Listo para Transformar tu Negocio?
Hablemos sobre cómo nuestras soluciones pueden ayudarte a alcanzar tus objetivos. Ponte en contacto con nuestros expertos hoy mismo.
Hablar con un ExpertoTags:
Equipo Arvucore
El equipo editorial de Arvucore está formado por profesionales experimentados en desarrollo de software. Estamos dedicados a producir y mantener contenido de alta calidad que refleja las mejores prácticas de la industria e insights confiables.
Preguntas frecuentes
- ¿Cuál es la diferencia entre Redis y Memcached?
- Memcached es una caché clave-valor simple y multihilo para strings. Redis añade estructuras de datos, persistencia, replicación, clúster, scripts Lua y pub/sub. Elige Memcached para caché de objetos simples con concurrencia muy alta; elige Redis cuando necesites cualquier cosa más allá de get/set.
- ¿Qué patrón de caché debería usar por defecto?
- Cache-aside. La aplicación lee la caché, recurre a la base de datos en caso de miss y escribe el resultado de vuelta con un TTL. Es simple, tolera caídas de la caché y funciona con cualquier store.
- ¿Qué es un cache stampede y cómo lo evito?
- Un stampede ocurre cuando una clave popular expira y muchas peticiones golpean la base de datos al mismo tiempo para reconstruirla. Evítalo con un lock por clave, coalescencia de peticiones dentro del proceso o expiración anticipada probabilística, que renueva la clave antes de que expire de verdad.
- ¿Cuánto debería durar el TTL de una caché?
- Tanto como el negocio tolere datos desactualizados, y ni un segundo más. Combina el TTL con invalidación explícita en las escrituras, para que el TTL sea solo una red de seguridad y no el mecanismo principal de frescura.
- ¿Qué hace stale-while-revalidate en la caché de una CDN?
- Permite que la CDN sirva de inmediato una respuesta expirada mientras obtiene una copia nueva del origen en segundo plano. El usuario nunca espera al origen, y el origen recibe una sola revalidación por edge en lugar de una ráfaga.
- ¿Qué tasa de aciertos (hit ratio) de caché es buena?
- Depende del coste de un miss, no de un número universal. Sigue la tasa de aciertos junto con la latencia p99 del origen y la carga de la base de datos; si una pequeña caída de la tasa dispara el p99, la caché está haciendo un trabajo crítico y necesita protección contra stampede.
Artículos relacionados

GraphQL vs REST en 2026: cuándo usar cada estilo de API
GraphQL vs REST comparados en fetching, caché, versionado, errores, N+1, seguridad y herramientas, con checklist de decisión por escenario y ejemplo lado a lado.

Arquitectura basada en eventos: sistemas resilientes y escalables
En Arvucore, exploramos cómo la arquitectura basada en eventos transforma los sistemas distribuidos modernos, permitiendo aplicaciones ágiles, resilientes y escalables. Este artículo examina los principios fundamentales, los patrones de diseño prácticos y las consideraciones operativas para la implementación de sistemas basados en eventos en entornos empresariales. Los lectores encontrarán orientación sobre opciones de arquitectura, estrategias de integración y beneficios mensurables para impulsar la agilidad empresarial y la solidez técnica en las implementaciones de producción.

Micro Frontends: Arquitectura Escalable para Grandes Aplicaciones
En Arvucore, exploramos cómo los micro frontends permiten una arquitectura frontend resiliente y modular para aplicaciones a gran escala. Al descomponer interfaces de usuario monolíticas en partes implementables de forma independiente, los equipos ganan autonomía, lanzamientos más rápidos y una propiedad más clara. Este artículo describe patrones de diseño, estrategias de integración, ventajas y desventajas en términos de rendimiento y enfoques de gobernanza para ayudar a los líderes empresariales y equipos técnicos europeos a evaluar los micro frontends para su próximo gran proyecto.

Arquitectura hexagonal en 2026: puertos, adaptadores y Clean
Hexagonal vs Clean vs Onion explicadas con un ejemplo real en TypeScript, estructura de carpetas, estrategia de tests y los errores que hunden a la mayoría de equipos.