Estrategias de almacenamiento en caché: carga diferida y escritura simultánea
Implemente la carga diferida para llenar la caché cuando se produzcan fallos de caché y la escritura simultánea para mantenerla coherente con cada escritura en la base de datos
Estrategias de almacenamiento en caché: carga diferida y escritura simultánea es una lección gratuita de AWS Solutions Architect en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AWS Solutions Architect, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AWS Solutions Architect incluye 4 lecciones en total.
Por qué son importantes las estrategias de almacenamiento en caché
Insertar una caché entre la aplicación y la base de datos requiere una estrategia de almacenamiento en caché: un conjunto de reglas que determina cuándo se introducen los datos en la caché, cuándo se leen de ella y cuándo se expulsan. Elegir una estrategia incorrecta puede provocar datos obsoletos (la caché devuelve valores desactualizados), fallos en una caché fría (la caché está vacía y cada solicitud llega a la base de datos) o una avalancha de solicitudes a la caché (muchas solicitudes simultáneas para la misma clave ausente llegan a la base de datos al mismo tiempo). Las dos estrategias fundamentales son la carga diferida y la escritura simultánea.
Carga diferida (Cache-Aside): cómo funciona
La carga diferida (también denominada cache-aside) es el patrón de almacenamiento en caché más común. La aplicación comprueba primero la caché. Si se produce un acierto de caché, los datos se devuelven directamente desde la caché: es la ruta rápida. Si se produce un fallo de caché, la aplicación obtiene los datos de la base de datos, escribe el resultado en la caché con un TTL y lo devuelve al solicitante. La caché solo se llena con datos que se solicitan realmente, de ahí el término «diferida». La siguiente solicitud de la misma clave la encontrará en la caché.
# Lazy loading pattern (Python with redis-py)
def get_user(user_id, redis_client, db):
cache_key = f'user:{user_id}'
# 1. Check cache
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached) # Cache HIT
# 2. Cache MISS: fetch from DB
user = db.query('SELECT * FROM users WHERE id = %s', user_id)
# 3. Populate cache with TTL of 300 seconds
redis_client.setex(cache_key, 300, json.dumps(user))
return userCarga diferida: ventajas
La carga diferida tiene tres ventajas principales: solo se almacenan en caché los datos solicitados; la caché no se llena con datos que nadie lee, por lo que la memoria se utiliza de forma eficiente. Una caché fría no interrumpe la aplicación: ante un fallo de caché, la aplicación recurre a la base de datos, de modo que, aunque ElastiCache se reinicie o falle un nodo, la aplicación sigue funcionando, aunque con mayor latencia. La caché siempre mantiene coherencia eventual con la base de datos, porque los datos obsoletos caducan mediante el TTL, incluso si no se detectaron algunas actualizaciones.
Carga diferida: desventajas
La carga diferida tiene tres desventajas principales: los fallos de caché son costosos: requieren tres operaciones (comprobar la caché, leer la base de datos y escribir en la caché), frente a una sola en caso de acierto, lo que provoca una mayor latencia en las solicitudes en frío. Datos obsoletos: después de una actualización de la base de datos, la caché sigue proporcionando el valor antiguo hasta que caduca el TTL o se invalida explícitamente la clave (ventana de incoherencia de la caché). Avalancha de solicitudes a la caché: si caduca una clave popular, muchas solicitudes simultáneas sufren un fallo de caché y acceden a la base de datos al mismo tiempo, lo que puede sobrecargarla.
# Mitigating cache stampede with a probabilistic early expiration
# (Refresh the key before it expires to avoid simultaneous misses)
def get_with_stampede_protection(key, redis_client, db_fetch_fn, ttl=300):
value = redis_client.get(key)
ttl_remaining = redis_client.ttl(key)
# Probabilistically refresh before expiry
if value is None or (ttl_remaining < 30 and random.random() < 0.1):
value = db_fetch_fn()
redis_client.setex(key, ttl, json.dumps(value))
return json.loads(value)Escritura simultánea: cómo funciona
En la estrategia de escritura simultánea, cada escritura en la base de datos también se realiza en la caché al mismo tiempo. La aplicación escribe tanto en la caché como en la base de datos como parte de la misma operación (o la base de datos activa una actualización de la caché). Por lo tanto, la caché siempre está sincronizada con la base de datos y no existe una ventana de datos obsoletos. La escritura simultánea garantiza que los datos de la caché estén siempre actualizados, por lo que las lecturas posteriores de datos escritos recientemente siempre son aciertos de caché.
# Write-through pattern (Python)
def update_user(user_id, user_data, redis_client, db):
# 1. Write to database FIRST
db.execute('UPDATE users SET name=%s WHERE id=%s',
(user_data['name'], user_id))
# 2. Update cache immediately (write-through)
cache_key = f'user:{user_id}'
redis_client.setex(cache_key, 3600, json.dumps(user_data))
return user_data
# Every read is now a cache hit for recently updated dataEscritura simultánea: ventajas
Ventajas de la escritura simultánea: los datos de la caché siempre están actualizados; no hay datos obsoletos porque la caché se actualiza en cada escritura. Las lecturas siempre son rápidas: los datos populares que se escriben con frecuencia siempre están en la caché. No se producen avalanchas de solicitudes durante las lecturas: como los datos se precargan antes de leerse, no hay fallos en frío para los datos escritos recientemente. Esta estrategia es ideal para cargas de trabajo con muchas lecturas y actualizaciones frecuentes en las que la frescura de los datos es crítica, como catálogos de productos, sistemas de precios o cachés de perfiles de usuario.
Escritura simultánea: desventajas
Desventajas de la escritura simultánea: penalización de escritura: cada escritura implica dos operaciones (base de datos y caché), lo que añade latencia a las escrituras. Contaminación de la caché: los datos se almacenan en la caché aunque no vuelvan a leerse nunca (se escriben una vez y nunca se solicitan), lo que desperdicia memoria de la caché. El reinicio de la caché provoca una caché fría: si se reinicia el clúster de caché, se pierden todos los datos escritos de forma preventiva y la caché debe volver a llenarse mediante escrituras o un proceso de precalentamiento. Combine la escritura simultánea con un TTL para evitar el crecimiento ilimitado de datos almacenados en caché que se leen con poca frecuencia.
Combinación de carga diferida y escritura simultánea
En la práctica, muchos sistemas de producción combinan ambas estrategias: utilizan la escritura simultánea para los datos que se actualizan y leen con frecuencia (como las sesiones de usuario o los precios actuales) y la carga diferida para los datos que se actualizan pocas veces y se leen con frecuencia (como las descripciones de productos o el contenido de artículos). Establezca TTL adecuados en ambos casos: las claves de escritura simultánea reciben un TTL largo, ya que los datos siempre están actualizados; las claves cargadas de forma diferida reciben un TTL más corto para limitar la ventana de datos obsoletos. Este enfoque híbrido maximiza la tasa de aciertos de caché y minimiza la obsolescencia.
# Hybrid: write-through for sessions, lazy loading for product data
# Write-through for session data (always fresh, critical)
def save_session(session_id, data, redis_client, db):
db.upsert('sessions', session_id, data)
redis_client.setex(f'session:{session_id}', 3600, json.dumps(data))
# Lazy loading for product catalog (infrequent updates OK)
def get_product(product_id, redis_client, db):
cached = redis_client.get(f'product:{product_id}')
if cached:
return json.loads(cached)
product = db.query('SELECT * FROM products WHERE id=%s', product_id)
redis_client.setex(f'product:{product_id}', 86400, json.dumps(product))
return productPrincipios de diseño del TTL
El Time-To-Live (TTL) de los datos almacenados en caché controla la duración máxima de la ventana de datos obsoletos y el uso de memoria de la caché. Diseñe los TTL según los siguientes factores: frecuencia de actualización de los datos (los datos de sesión cambian a menudo → TTL corto; el contenido estático cambia pocas veces → TTL largo), tolerancia a la obsolescencia (precios financieros → muy corta; texto de una entrada de blog → horas o días) y capacidad de memoria de la caché (poca memoria → TTL más corto para expulsar antes los datos obsoletos). Establezca siempre un TTL: nunca almacene datos en caché sin caducidad, ya que la caché acabará llenándose de datos obsoletos.
# TTL examples by data type
# API rate limit counter: 60 seconds
redis_client.setex(f'ratelimit:{ip}', 60, count)
# User session: 30 minutes
redis_client.setex(f'session:{id}', 1800, json.dumps(session))
# Product catalog: 24 hours
redis_client.setex(f'product:{id}', 86400, json.dumps(product))
# Stock price: 10 seconds
redis_client.setex(f'price:{symbol}', 10, price)
# Static site content: 7 days
redis_client.setex(f'page:{slug}', 604800, html_content)Invalidación de la caché al actualizar
En lugar de depender únicamente de la caducidad del TTL, puede invalidar explícitamente (eliminar) las claves de la caché cuando cambien los datos subyacentes. Esto elimina por completo la ventana de datos obsoletos. Patrones habituales: eliminación al escribir (eliminar la clave de la caché después de cada actualización de la base de datos; la siguiente lectura la vuelve a cargar mediante carga diferida) e invalidación basada en eventos (DynamoDB Streams o la captura de cambios de RDS activa una función Lambda que elimina las claves afectadas). La invalidación de caché es uno de los problemas más difíciles de los sistemas distribuidos; cuanto más sencilla sea la lógica de invalidación, más fiable será la caché.
# Delete-on-write invalidation pattern
def update_product(product_id, new_data, redis_client, db):
# Update the database
db.execute('UPDATE products SET ... WHERE id=%s', (product_id,))
# Invalidate the cache key
redis_client.delete(f'product:{product_id}')
# Also invalidate any list/search caches that may include this product
redis_client.delete('products:list:page:1')
redis_client.delete(f'products:category:{new_data["category_id"]}')
# Next read will trigger lazy loading with fresh dataAlmacenamiento en caché con escritura diferida (Write-Back)
Un patrón menos habitual, pero potente, es la escritura diferida (write-back): la aplicación escribe únicamente en la caché y esta vacía los datos de forma asíncrona en la base de datos en segundo plano. Esto proporciona escrituras extremadamente rápidas (solo en memoria), a cambio de una posible pérdida de datos si la caché falla antes de vaciarlos. La escritura diferida es adecuada para escrituras de alta frecuencia y gran volumen en las que los datos se pueden reconstruir o se aceptan pequeñas pérdidas, como contadores de visitas, eventos de análisis o actualizaciones de puntuaciones de videojuegos. ElastiCache no admite de forma nativa la escritura diferida; debe implementarse en la capa de aplicación.
# Write-behind pattern: write to cache, flush to DB asynchronously
# Application writes:
# redis_client.incr('post:42:views') # fast, in-memory only
# Background job (runs every 60 seconds):
def flush_view_counts(redis_client, db):
for key in redis_client.scan_iter('post:*:views'):
count = redis_client.getdel(key) # atomic get-and-delete
post_id = key.split(':')[1]
db.execute('UPDATE posts SET views = views + %s WHERE id = %s',
(int(count), post_id))Comprobación rápida
Ponga a prueba su comprensión de los conceptos de AWS Solutions Architect (SAA-C03) de esta lección.
Resumen de la lección
En esta lección ha aprendido que la carga diferida llena la caché cuando se producen fallos de lectura y utiliza la memoria de forma eficiente, pero puede proporcionar datos obsoletos hasta que caduque el TTL; la escritura simultánea actualiza la caché en cada escritura, lo que elimina los datos obsoletos, pero desperdicia memoria con datos que no se leen; y la invalidación explícita elimina las claves de la caché cuando se actualiza la base de datos para eliminar las ventanas de datos obsoletos. A continuación, exploraremos el almacenamiento de sesiones y los patrones de tablas de clasificación con ElastiCache.
Preguntas frecuentes
¿La lección «Estrategias de almacenamiento en caché: carga diferida y escritura simultánea» es gratis?
Sí — el texto completo de «Estrategias de almacenamiento en caché: carga diferida y escritura simultánea» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AWS Solutions Architect, actualiza a CoddyKit PRO. El curso de AWS Solutions Architect incluye 4 lecciones en total.
¿Qué aprenderé en «Estrategias de almacenamiento en caché: carga diferida y escritura simultánea»?
Implemente la carga diferida para llenar la caché cuando se produzcan fallos de caché y la escritura simultánea para mantenerla coherente con cada escritura en la base de datos Practicas AWS Solutions Architect con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AWS Solutions Architect?
No se requiere experiencia previa. AWS Solutions Architect en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Estrategias de almacenamiento en caché: carga diferida y escritura simultánea»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AWS Solutions Architect?
Sí. Cada lección de AWS Solutions Architect incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Redis frente a Memcached: elección del motor adecuado
- Grupos de replicación y modo de clúster de ElastiCache Redis
- Estrategias de almacenamiento en caché: carga diferida y escritura simultánea
- Almacenamiento de sesiones y patrones de tablas de clasificación