3.15

Ver en inglés

3.15 Caché y entrega de contenido

Visión general y motivación

Un caché es una copia de datos alojada en un lugar más rápido o más cercano que el original, de modo que puedas responder a una petición sin repetir el trabajo completo y costoso. Casi todo lo que nos parece veloz es veloz gracias al caché. La consulta a la base de datos que habría tardado 40 milisegundos se resuelve en menos de uno cuando su resultado ya descansa en memoria. La imagen que habría cruzado un océano se sirve desde un servidor de la misma ciudad. El caché es la técnica de rendimiento de mayor alcance que existe, y también la que con más probabilidad te entregará un fallo sutil y desesperante.

Este capítulo profundiza en la estrategia de caché. El capítulo 3.4 (arquitectura de datos y almacenamiento) introduce los cachés y las redes de distribución de contenido como una preocupación de almacenamiento entre muchas otras, y el capítulo 3.13 (redes y conectividad) cubre la ruta de red por la que viajan. Aquí llegarás a las decisiones: dónde colocar un caché, cómo construir su clave, cuándo invalidarlo, cómo protegerlo bajo carga y cómo razonar sobre la obsolescencia que cambias por velocidad. El caché toca la ingeniería de rendimiento (capítulo 2.16), la escalabilidad y la resiliencia (capítulo 3.5), las realidades del fallo parcial en sistemas distribuidos (capítulo 3.3) y, como un caché envenenado puede servir un ataque a miles de usuarios, la seguridad de aplicaciones (capítulo 4.2).

La motivación se reduce a tres palancas. El caché reduce la latencia, de modo que los usuarios esperan menos. Reduce la carga, de modo que tu origen atende más tráfico con el mismo hardware. Y reduce el coste, porque una petición respondida en el borde nunca toca tu base de datos, tu cómputo ni tu factura de egreso. En equipos grandes, una estrategia de caché compartida es la diferencia entre una plataforma que escala de forma predecible y una en la que cada servicio reinventa la invalidación y la acierta mal. En sistemas empresariales y gubernamentales, donde el tráfico se dispara en fechas límite de presentación o en días de lanzamiento, un caché bien diseñado suele ser lo que separa un portal que funciona de un fallo público.

Principios clave

  • Utiliza el caché para reducir latencia, carga y coste, y ten claro cuál de los tres estás adquiriendo.
  • Coloca los cachés en la capa correcta de la jerarquía, lo más cerca posible de donde aportan más.
  • Trata la invalidación como la parte difícil; diseña las claves y los tiempos de vida antes de cachear.
  • Protege el caché bajo carga con agrupación, dispersión aleatoria y defensas contra la avalancha.
  • Elige un patrón de escritura a propósito: la consistencia y la velocidad tiran en direcciones opuestas.
  • Mide la tasa de aciertos, la obsolescencia y la carga en el origen; un caché no medido es un pasivo.
  • Trata el contenido en caché como una superficie de ataque; un caché envenenado afecta a todos.

Recomendaciones

Comprender la jerarquía de caché

El caché no es una sola cosa en un solo lugar. Es una jerarquía de copias, cada una más cercana al usuario que la anterior, y debes diseñar en su totalidad. Lo más cercano al usuario es el caché del cliente: el caché HTTP del navegador, el almacén local de una aplicación móvil, un caché en memoria dentro del proceso. A continuación está la red de distribución de contenido (CDN), una flota de servidores distribuidos por todo el mundo que mantiene copias de tu contenido en el borde de la red, cerca de los usuarios. Detrás se encuentra el caché del proxy inverso o de la pasarela, un caché compartido que protege a tus servidores. Luego el caché de aplicación: un almacén clave-valor rápido, como una parrilla de datos en memoria, que guarda resultados calculados, sesiones y fragmentos renderizados. Y por último, el propio caché de consultas y de búfer de la base de datos, que mantiene en memoria las páginas más solicitadas para tocar el disco lo menos posible.

Cada capa cumple un trabajo distinto: el caché del cliente elimina la petición por completo, la CDN absorbe el tráfico de lectura global, el proxy inverso protege al origen del trabajo repetido e idéntico, el caché de aplicación ahorra el recálculo y el caché de la base de datos mantiene el almacén ágil. Una petición que falla en todas las capas y alcanza la base de datos es el camino más lento y más costoso que tienes, así que el punto de la jerarquía es responder lo más arriba y lo más cerca que puedas de forma segura. Dísénalo como un sistema, porque un fragmento en caché a nivel de aplicación y una copia obsoleta de la CDN por encima pueden contradecirse de formas que confunden al usuario.

Tratar la invalidación como el problema difícil

Hay una vieja broma de que los dos problemas más difíciles de la informática son dar nombres a las cosas, la invalidación de caché y los errores de uno. La broma perdura porque la invalidación realmente es difícil: un caché es una copia, y en el instante en que el original cambia, cada copia es un potencial engaño. Tienes tres estrategias amplias. La expiración basada en tiempo, con un tiempo de vida o TTL (la duración durante la cual una entrada se considera válida antes de que sea tratada como obsoleta), es la más sencilla: aceptas una obsolescencia acotada y dejas que las entradas envejecen. La invalidación explícita purga o actualiza las entradas cuando cambian los datos subyacentes, lo cual es preciso pero exige saber en cada rincón dónde vive una copia. La invalidación basada en eventos suscribe a los cachés a eventos de cambio para que se refresquen solos, lo que escala mejor entre muchos cachés pero añade una dependencia de mensajería.

La mayoría de los sistemas reales combinan estas estrategias: TTL cortos para datos que cambian a menudo y toleran unos segundos de obsolescencia, TTL largos más purga explícita para datos que cambian raramente pero que deben ser correctos cuando lo hacen, y claves de caché versionadas para contenido que es inmutable una vez publicado. El truco de la clave versionada conviene interiorizarlo: en lugar de invalidar, cambias la clave. Una hoja de estilos servida como app.v187.css nunca necesita purga, porque una nueva versión es una nueva clave y la anterior simplemente deja de solicitarse. Cuantas veces puedas transformar un problema de invalidación en un problema de nombramiento, hazlo.

Diseñar claves y TTL a propósito

Un caché es tan bueno como su clave. La clave de caché es el identificador bajo el que se almacena y consulta un valor, y equivocarla produce dos fallos opuestos. Demasiado gruesa, y sirves los datos de un usuario a otro: una página personalizada cachéada bajo una URL que ignora la identidad del usuario es una fuga de datos. Demasiado fina, y tu tasa de aciertos se derrumba porque ninguna dos peticiones comparten clave. Decide a propósito qué pertenece a la clave: la identidad del recurso más todo aquello que legítimamente varíe la respuesta (idioma, moneda, clase de dispositivo) y nada que no varíe. Normaliza las claves para que diferencias triviales como el orden de los parámetros de consulta no fragmenten el caché.

Los TTL merecen la misma reflexión. Un TTL es una promesa sobre la obsolescencia máxima que estarás dispuesto a servir, así que fíjalo desde la tolerancia real de los datos, no desde un número redondo que alguien adivinó: un cotizador de bolsa tolera segundos, un catálogo de productos minutos, una regulación publicada horas o una clave versionada sin expiración alguna. Añade una pequeña dispersión aleatoria, llamada jitter, para que un lote de entradas escritas juntas no expiren todas en el mismo instante y arremeten contra el origen. Escribe estas decisiones por escrito, porque un TTL sin justificación es un número que al próximo ingeniero le daría miedo modificar.

Protegerse de las avalanchas y agrupar peticiones

Cuando una entrada popular en caché expira, cada petición que la quería falla a la vez y se precipita contra el origen juntas. Esto es la avalancha de caché, también llamada efecto horda, y puede tumbar la misma base de datos que el caché pretendía proteger. Construye las defensas una vez y reutilízalas en todas partes. La agrupación de peticiones (single-flight) permite que solo la primera petición por una clave ausente recalcule el valor mientras las demás esperan su resultado, de modo que mil fallos simultáneos producen una sola llamada al origen. El recálculo anticipado probabilístico refresca una entrada caliente de forma aleatoria un instante antes de que expire, para que una petición de fondo la renueve antes de que la multitud vea un fallo. Una política de stale-while-revalidate sirve la copia ligeramente obsoleta de inmediato y la refresca de forma asincrónica, para que los usuarios nunca esperen a un fallo.

Estos patrones importan más precisamente cuando más necesitas el caché, bajo carga pico, así que validalos a escala realista: una defensa que funciona con diez usuarios puede seguir fallando con diez mil. Acopla estas prácticas con los patrones de resiliencia del capítulo 3.5, especialmente los temporizadores y los circuitos cortacircuitos, para que cuando el origen sea genuinamente lento, tu capa de caché lo proteja en lugar de apretar. El objetivo es un caché que se comporta mejor bajo presión, no uno que amplifica un pico hasta convertirlo en una caída.

Elegir un patrón de escritura a propósito

Cómo manejas las escrituras decide qué tan fresco se mantiene tu caché y cuánto arriesgas ante un fallo. Hay cuatro patrones comunes. En cache-aside (carga perezosa), la aplicación consulta el caché y, ante un fallo, lee del origen, puebla el caché y devuelve el valor; las escrituras van al origen e invalidan la entrada. Es el valor por defecto por buena razón: es simple y el caché solo guarda lo que se solicita. En write-through, cada escritura va al caché y al origen a la vez, de modo que el caché siempre está al día, al precio de la latencia de escritura y de cachear datos que quizás nadie lea. En write-back (write-behind), las escrituras caen primero en el caché y se descargan al origen de forma asincrónica, acelerando las escrituras pero arriesgando pérdida si el caché muere antes de la descarga. En write-around, las escrituras van directo al origen y saltan el caché, evitando el desgaste por datos de escritura intensiva que rara vez se releen, al precio de un fallo garantizado en la primera lectura.

Elige por carga de trabajo, no una vez para todo el sistema. Un catálogo intensivo en lecturas se adapta al cache-aside o al write-through. Un registro o un flujo de métricas intensivo en escrituras se adapta al write-around, para que el caché no se desgaste con datos que nadie releerá. El write-back conviene para escrituras de alto rendimiento donde un riesgo pequeño y comprendido de pérdida es aceptable y la durabilidad se resuelve en otro lugar. Declara el patrón de cada caché de forma explícita, porque quien asume cache-aside mientras el código ejecuta write-back malinterpretará tanto la frescura como el comportamiento ante fallos.

Ajustar la política de expulsión al patrón de acceso

Un caché tiene un tamaño fijo, así que cuando se llena, algo debe salir. La política de expulsión decide qué. La menos recientemente usada (LRU) expulsa la entrada que lleva más tiempo sin usarse, apostando a que el uso reciente predice el uso futuro, y es un valor por defecto sensato. La menos frecuentemente usada (LFU) expulsa la entrada con menos accesos, lo que conviene para conjuntos calientes estables donde pocos elementos son popularmente perennes, pero puede aferrarse a entradas que fueron calientes una vez y nunca se adaptan. Variantes como LRU segmentado y políticas adaptativas combinan recencia y frecuencia; la primero entrado, primero salido (FIFO) y la expiración temporal simple son más baratas, pero más brutas.

Ajusta la política a cómo se accede a tus datos: LFU o una política sensible a la frecuencia para un conjunto caliente pequeño que rara vez cambia, LRU donde la popularidad se desplaza en el tiempo, como con noticias o contenido en tendencia. Sea cual sea la que elijas, dimensiona el caché para que el conjunto caliente quepa, porque un caché demasiado pequeño para contener el conjunto de trabajo sufre thrashing, expulsando entradas justo antes de que se necesiten de nuevo. Vigila la tasa de expulsión como una métrica de primer orden, ya que un aumento repentino suele indicar que el caché está subdimensionado o que una explosión de claves lo está fragmentando.

Usar la semántica de caché HTTP correctamente

La web tiene un modelo de caché maduro y estandarizado incorporado a HTTP, y usarlo bien te regala el caché del cliente y el de la CDN sin más. La cabecera Cache-Control es la superficie de control: max-age fija la vida de frescura, public y private dicen si los cachés compartidos pueden almacenar la respuesta, no-store prohíbe el caché y stale-while-revalidate permite servir una copia obsoleta mientras se refresca. La validación permite a un caché comprobar la frescura a bajo coste sin volver a descargar el cuerpo. Un ETag (identificador de entidad) es un identificador de versión opaco que el servidor adjunta a una respuesta; el cliente lo devuelve en la cabecera If-None-Match, y el servidor responde 304 Not Modified sin cuerpo si nada cambió. Last-Modified con If-Modified-Since hace lo mismo usando marcas de tiempo.

La disciplina práctica es ser explícito. Establece Cache-Control en cada respuesta en lugar de dejar que los cachés adivinen con heurísticas. Marca como private o no-store las respuestas privadas y por usuario para que un proxy compartido nunca las almacene, un error común y peligroso. Usa URLs versionadas con un max-age largo y la directiva immutable para recursos estáticos, y validación con ETags para contenido que cambia de forma impredecible. Poner estas cabeceras en su sitio convierte toda la capa de cliente y CDN en un caché correcto, estandarizado y sin que lo hayas tenido que construir.

Empujar el trabajo al borde con CDN y cómputo de borde

Una CDN empezó como una forma de cachear archivos estáticos cerca de los usuarios, y aún lo hace de maravilla: imágenes, scripts, vídeo y descargas servidos desde una ubicación de borde a milisegundos de distancia en lugar de un origen lejano. Las CDN modernas van más allá. Cachéan contenido dinámico y personalizado con claves de grano fino, terminan TLS en el borde, absorben picos de tráfico y ataques de denegación de servicio distribuidos, y cada vez más ejecutan tu código. El cómputo de borde ejecuta lógica en las propias ubicaciones de borde, para que puedas personalizar una respuesta, verificar la autorización o ensamblar un fragmento de página sin un viaje de ida y vuelta a una región central.

Aprovecha esto para las lecturas que dominan la mayoría de los sistemas. Coloca los recursos estáticos detrás de la CDN con URLs versionadas de larga vida, cachéa las respuestas de API en el borde donde la frescura lo permita (con claves cuidadosas para que la personalización no se filtre), y usa el cómputo de borde para lógica sensible a la latencia y ligera, cerca de los usuarios. El intercambio es alcance frente a control: el borde es rápido y cercano, pero está lejos de tus datos y es más difícil de depurar, así que mantén en el origen lo que requiera consistencia fuerte o estado autoritativo fresco, y deja que el borde maneje el vasto tráfico de lectura cachéable.

Tratar el caché como superficie de ataque

Un caché sirve la misma respuesta almacenada a muchos usuarios, lo que lo convierte en objetivo. El envenenamiento de caché es un ataque en el que una petición es diseñada para que el caché almacene una respuesta nociva o controlada por el atacante y luego la sirva a todos los que vengan después. Normalmente explota una entrada no incluida en la clave: una cabecera que la aplicación refleja en la respuesta pero que el caché ignora al construir la clave. El ataque relacionado de decepción de caché web engaña a un caché para que almacene la respuesta privada de una víctima bajo una URL pública. Ambos son fallos de claveado y de confiar en las entradas, tratados de forma más amplia en el capítulo 4.2.

Defiéndete a propósito. Incluye en la clave de caché cada entrada que pueda cambiar la respuesta y niega reflejar cabeceras no claveadas en cuerpos cachéados. Nunca dejes que un caché compartido almacene respuestas autenticadas y por usuario bajo una clave compartida. Normaliza y valida las rutas y parámetros de petición antes de cachear. Configura Vary correctamente para que los cachéen particionen las respuestas por las cabeceras que realmente importan, como la codificación de contenido o el idioma. Como una sola entrada envenenada daña a cada usuario aguas abajo, trata la configuración de caché como código sensible a la seguridad y revísalo como tal.

Hacer que el comportamiento del caché sea observable

No puedes gestionar un caché que no puedes ver. La métrica clave es la tasa de aciertos: la fracción de peticiones servidas desde el caché en lugar del origen. Una tasa que cae silenciosamente del 95 al 70 por ciento puede multiplicar la carga del origen varias veces y preceder a una caída, y solo la captarás a tiempo si la vigilas. Instrumenta cada capa por separado, porque una tasa de aciertos saludable en la CDN puede esconder una tasa colapsando en el caché de aplicación debajo. Esta es la cara específica del caché de las prácticas de observabilidad del capítulo 9.2.

Registra más que aciertos: tasa de expulsión y presión de memoria para detectar subdimensionamiento, latencia en cada capa para confirmar que el caché es realmente más rápido, tasa de peticiones al origen para ver cuánta carga absorbe, y obsolescencia (la antigüedad de las entradas servidas) para confirmar que cumples tus promesas de frescura. Alértate de las proporciones que predicen problemas, sobre todo una tasa de aciertos en descenso o una tasa de expulsión en ascenso, para que sepas de un caché que se deteriora por un panel de control antes de que lo sepan los usuarios. Un caché observado es un activo que puedes ajustar; uno no observado es una dependencia oculta a la espera de sorprenderte.

Compensaciones: ventajas y desventajas

El caché compra velocidad y escala con la moneda de la frescura y la complejidad. Cada caché es una apuesta de que lo obsoleto pero rápido supera a lo fresco pero lento para ese dato en particular, y el arte es colocar esa apuesta con conciencia y no por defecto. La tabla siguiente resume las elecciones principales.

ElecciónVentajasDesventajas
Cache-asideSimple; solo cachéa lo que se leeLa primera lectura siempre falla; riesgo de obsolescencia breve tras escrituras
Write-throughEl caché siempre está actualizado tras escrituraEscrituras más lentas; cachéa datos que quizás nadie lea
Write-backEscrituras muy rápidas; absorbe ráfagasRiesgo de pérdida de datos si el caché falla antes de descargar
Write-aroundEvita desgastar el caché con datos intensivos en escrituraFallo garantizado en la primera lectura
TTL cortoObsolescencia acotada y pequeñaMenor tasa de aciertos; más carga al origen
TTL largo / claves versionadasAlta tasa de aciertos; baja carga al origenObsolescencia salvo que se invalide; requiere claves disciplinadas
CDN y bordeBaja latencia global; absorbe picosLejos de los datos; más difícil de depurar e invalidar
Expulsión LRUSe adapta a popularidad cambiantePuede expulsar un conjunto caliente estable bajo carga de escaneo
Expulsión LFUProtege un conjunto caliente estableLenta para adaptarse; se aferra a entradas ya no calientes

La tensión recurrente es consistencia frente a rendimiento. Un caché con TTL largo y alta tasa de aciertos es rápido y barato, pero puede servir datos obsoletos; un caché con TTL corto e invalidación agresiva es fresco y correcto, pero trabaja al origen más duro. No hay una respuesta universalmente correcta, solo una respuesta correcta por cada dato, fijada por su tolerancia real a la obsolescencia. La segunda tensión es simplicidad frente a alcance: un caché de aplicación está cerca de tus datos y es fácil de razonar, mientras que el borde está lejos, es rápido y más difícil de invalidar. Resuelve ambas clasificando tus datos por necesidad de frescura y volumen de lectura, y colocando y configurando cada clase a propósito.

Preguntas para debatir con tu equipo

  1. ¿Cuál es la tolerancia real a la obsolescencia de cada tipo de dato que cachéamos, y hemos fijado TTLs e invalidación desde esa tolerancia en lugar de por costumbre? La mayoría de los equipos cachéa con un TTL que alguien eligió una vez y nunca revisó, de modo que algunos datos se sirven más obsoletos de lo que el negocio puede aceptar mientras otros expiran tan agresivamente que el caché apenas ayuda. Trae tus diez recursos más cachéados y, para cada uno, pregunta a quien posee ese dato qué tan obsoleto puede ser sin peligro: segundos, minutos, horas o nunca una vez publicado. Normalmente encontrarás que las respuestas varían enormemente y que tus TTLs actuales no se ajustan. El resultado que buscas es una clasificación breve de frescura, cada clase mapeada a un enfoque (TTL corto, TTL largo más purga, o claves inmutables versionadas), para que las decisiones de caché fluyan de la semántica de los datos y no de conjeturas.

  2. Si nuestra entrada de caché más popular expirara ahora mismo bajo tráfico pico, ¿qué le pasaría al origen? Esta pregunta revela si tienes protección real contra la avalancha o solo esperanza. Muchos sistemas funcionan bien hasta que una clave caliente expira durante un pico de tráfico y cada petición arremete contra la base de datos a la vez, convirtiendo el caché de escudo en detonador. Recorre el camino de forma concreta para tu extremo más concurrido: ¿hay agrupación de peticiones para que solo un fallo alcance al origen?, ¿hay jitter para que las entradas no expiren en bloque?, ¿hay una política de stale-while-revalidate para que los usuarios nunca esperen a una recarga? Trae evidencia de pruebas de carga, no intuiciones, porque una defensa contra la avalancha que aguanta con diez usuarios puede seguir colapsando con diez mil. Si no puedes responder con confianza, tu próxima inversión en resiliencia acaba de encontrarte.

  3. ¿Estamos seguros de que ningún caché compartido almacena nunca datos privados de un usuario bajo una clave que otro puede alcanzar? Este es el error de caché que se convierte en incidente de seguridad y titular. Ocurre cuando una respuesta personalizada o autenticada se cachéa bajo una clave que omite la identidad del usuario, o cuando falta una cabecera Cache-Control pensada para mantener una respuesta privada, y un proxy o CDN compartido la almacena y se la sirve al siguiente. Audita qué respuestas son cachéables en capas compartidas, confirma que cada respuesta por usuario está marcada como private o no-store, y confirma que cada clave de caché incluye cada entrada que cambia la respuesta. Trátalo como revisión de seguridad, porque el radio de impacto es cada usuario aguas abajo, y conéctalo con las prácticas del capítulo 4.2.

  4. ¿Qué patrón de escritura usa realmente cada uno de nuestros cachés, y alguien lo eligió a propósito? Cache-aside, write-through, write-back y write-around hacen promesas opuestas sobre frescura y sobre lo que pierdes cuando el caché falla, y en la mayoría de los códigos base el patrón es lo que el autor original copió de pasada. Para un equipo grande, esto importa porque un servicio que asume frescura cache-aside mientras otro ejecuta en secreto write-back puede producir datos que parecen corruptos pero solo están obsoletos, y el ingeniero en turno pierde horas persiguiendo un fantasma. Trae un inventario por caché: el patrón de escritura, la frescura que garantiza y qué pasa con las escrituras no descargadas si el proceso muere. Donde un caché use write-back, trae el argumento de durabilidad que lo respalda. En sistemas empresariales y gubernamentales que manejan datos financieros o de registro, un caché write-back sin garantía de respaldo es una observación de auditoría a la espera de ocurrir, así que la discusión debe terminar con el patrón de cada caché nombrado, justificado y documentado.

  5. Cuando desplegamos o cambiamos datos, ¿cada capa de caché relevante se invalida correctamente, o confiamos en que alguien se acuerde de purgar? La invalidación es la parte difícil, y el modo de fallo es silencioso: un valor corregido que sigue equivocado durante horas porque una capa de la jerarquía, una CDN, un proxy inverso o un caché de aplicación, nunca recibió el mensaje. Una organización grande multiplica este riesgo, porque un cambio lógico único puede necesitar propagarse por muchos cachés en muchas regiones pertenecientes a distintos equipos. Trae un rastro concreto de un cambio reciente de datos y síguelo por cada capa de caché, preguntando en cada una: ¿qué desencadenó la invalidación aquí y cuánto tardó? Prefiere diseños que conviertan la invalidación en nombramiento (claves versionadas) o en eventos (un cambio publica una purga) antes que manuales de ejecución. En sistemas del sector público donde una cifra publicada errónea, una tasa impositiva o una cantidad de beneficio, puede tener peso legal, una brecha de invalidación no es una molestia sino una exposición de cumplimiento, así que el resultado debe ser una ruta de invalidación mapeada para cada clase de datos cachéados.

  6. ¿Estamos tratando el caché como infraestructura de plataforma compartida, o cada equipo reinventa claves, invalidación y protección contra avalancha por su cuenta? El caché bien hecho es un pequeño conjunto de problemas difíciles resueltos una vez: claves normalizadas, invalidación basada en eventos, agrupación de peticiones, semántica HTTP correcta y observabilidad por capa. Cuando cada equipo improvisa estos, una organización grande paga los mismos errores repetidamente, y un fallo de envenenamiento o una fuga de datos privados arreglado en un servicio persiste en silencio en otros diez. Trae un mapa honesto de quién posee las convenciones de caché hoy y cuánto código de caché duplicado existe entre servicios. La consideración contraria es la autonomía: los equipos se resisten a una biblioteca compartida impuesta, así que valora una ruta pavimentada por defecto fácil de adoptar frente a un estándar duro que se impone. Para un grupo de plataforma empresarial o gubernamental, una capacidad de caché compartida y bien probada es también la forma más barata de hacer que los requisitos de seguridad y auditoría se mantengan de forma uniforme, así que la discusión debe decidir qué se convierte en infraestructura compartida y quién la financia.

Perspectiva sectorial

Startup. El caché es tu camino más barato para sobrevivir a un pico de tráfico que aún no puedes pagar escalar, así que gasta el poco tiempo que tienes en unas pocas colocaciones de alto rendimiento: una CDN con URLs versionadas para recursos estáticos, y una única capa cache-aside con TTL cortos y jitter frente a tu consulta más caliente. Apóyate en servicios gestionados de CDN y caché en lugar de correr los tuyos, y añade agrupación de peticiones pronto, porque una avalancha en un día de lanzamiento contra una base de datos pequeña es el fallo más probable para acabar mal un buen día. Deja los esquemas de invalidación elaborados hasta que los datos te digan que importan.

Pequeña empresa. Sin especialista en caché y con un presupuesto ajustado, prefiere comprar el caché que obtienes gratis dentro de herramientas que ya usas: una CDN incluida en tu alojamiento, cabeceras HTTP Cache-Control en las respuestas de tu framework web, y el caché de consultas integrado en tu base de datos. La decisión de construir o comprar casi siempre favorece comprar aquí, porque un caché mal claveado que filtra los datos de un cliente a otro cuesta mucho más que el servicio gestionado que evitaste. Logra las dos ganancias baratas: cabeceras HTTP correctas y nunca cachear páginas autenticadas en capas compartidas, y deja los patrones exóticos de lado.

Empresa. A escala y entre muchos equipos, el riesgo se desplaza de un solo caché a la inconsistencia entre ellos: esquemas de clave divergentes, invalidación desigual y fugas de datos privados que aparecen en un servicio y no en otro. Provee el caché como infraestructura de plataforma compartida con rutas pavimentadas por defecto para claves, invalidación, protección contra avalancha y observabilidad por capa, para que la tasa de aciertos, la expulsión y la obsolescencia sean visibles en un solo lugar y gobernadas de forma uniforme. Haz que la configuración de caché sea revisable como código sensible a la seguridad, y trata la invalidación entre regiones como un problema de diseño de primer orden en lugar de un manual de ejecución por equipo.

Sector público. Las restricciones de contratación y transparencia configuran qué puedes cachear y cómo demostrar que es seguro. Cachéa agresivamente el contenido público, guías, formularios y tablas de tasas, detrás de una CDN con TTL largos, para que un pico en fecha límite de presentación se absorba lejos del origen, y documenta esa configuración para auditoría. Las páginas autenticadas que muestran los registros de un ciudadano nunca deben tocar un caché compartido, y esa regla debe ser verificable, no simplemente afirmada. Donde una CDN o un servicio de caché se adquiera de un proveedor, exige que el contrato exponga los controles que necesitas (claveado, purga y registro) y evita la dependencia de un proveedor que atrape datos públicos en formatos de caché propietarios.

Ejemplos

Startup. Una pequeña aplicación de consumo envía su catálogo de productos por una capa cache-aside respaldada por un almacén en memoria, con un TTL de 60 segundos y jitter para que las entradas no expiren juntas. Los recursos estáticos van a una CDN con nombres de archivo versionados y un max-age de un año, de modo que un despliegue que cambia una hoja de estilos sirve una URL nueva y nunca necesita purga. Cuando un lanzamiento en un pódcast popular envía un pico de tráfico, la agrupación en single-flight significa que los miles de fallos simultáneos de la página de inicio producen una sola lectura de base de datos, no miles. Los fundadores gastan casi nada en caché y sin embargo manejan un pico que habría derretido su pequeña base de datos, porque colocaron unos pocos cachés bien elegidos a propósito.

Empresa. Un minorista global sirve a millones de compradores a través de un caché en capas: una CDN para imágenes y respuestas de API cachéables, un caché de proxy inverso compartido en cada región, y un caché de aplicación para precios calculados y fragmentos de inventario. Las claves de caché están normalizadas e incluyen moneda, idioma y clase de dispositivo, para que la personalización nunca se filtre y las tasas de aciertos se mantengan altas. Los datos de producto usan TTL cortos con invalidación basada en eventos, de modo que un cambio de precio publica a un bus de mensajes que purga las claves afectadas entre regiones en segundos. Cada capa informa tasa de aciertos, tasa de expulsión y obsolescencia a la plataforma de observabilidad del capítulo 9.2, y una alerta por caída de tasa de aciertos detectó una vez un caché subdimensionado antes de que se convirtiera en una caída en el proceso de pago.

Sector público. Una agencia tributaria nacional opera un portal de presentación que está tranquilo la mayor parte del año y desbordado cerca de la fecha límite. El equipo cachéa agresivamente donde es seguro y nunca donde no lo es. El contenido público (páginas de orientación, formularios, tablas de tasas) se sirve desde una CDN con TTL largos y URLs versionadas, absorbiendo el pico de lectura del día límite lejos del origen. Las páginas autenticadas que muestran la declaración de un ciudadano están marcadas como no-store y nunca tocan un caché compartido, para que ningún contribuyente reciba nunca los datos de otro. La configuración de caché se revisa como código sensible a la seguridad según las prácticas del capítulo 4.2, y la protección contra avalancha se prueba a escala de fecha límite meses antes, para que el portal que antes se doblaba en el día más concurrido del año ahora se mantenga firme.

Caso de negocio: motivaciones, retorno y coste total de propiedad

El retorno del caché es inusualmente directo y fácil de cuantificar. Un caché que eleva la tasa de aciertos del 80 al 95 por ciento reduce el tráfico al origen en tres cuartas partes, lo que puede significar posponer una actualización de base de datos, operar con menos servidores de aplicación o sobrevivir a un pico de tráfico que de otro modo habría requerido escalado de emergencia. Las mejoras de latencia se convierten en ingresos en el comercio y en satisfacción y tasas de finalización en servicios públicos, donde la investigación ha vinculado durante mucho tiempo las páginas más rápidas con mayor conversión y menor abandono. Los costes de egreso y cómputo bajan porque una petición servida desde el borde nunca paga por ancho de banda de origen ni por procesamiento. Para sistemas intensivos en lectura, que son la mayoría, el caché suele ser el rendimiento más barato que puedes comprar.

Peséa con honestidad el coste total de propiedad. Los costes directos son modestos: la infraestructura de CDN y caché es barata frente a la capacidad de origen que ahorra. El coste real es la disciplina de ingeniería, porque un caché incorrecto es peor que no tener caché. Los fallos de obsolescencia, los errores de invalidación y las vulnerabilidades de envenenamiento de caché llevan un coste real, y crecen cuando el caché se improvisa por equipo en lugar de proporcionarse como una capacidad compartida y bien probada. El caso de negocio más fuerte financia una pequeña cantidad de infraestructura y convención de caché compartida (claves estándar, invalidación, protección contra avalancha y observabilidad) para que cada equipo obtenga el beneficio sin repetir los errores. Planteado para la dirección, el caché se conecta con métricas que ya tracks: coste de infraestructura, latencia de página, tasas de conversión y finalización, y frecuencia de incidentes durante eventos pico.

Antipatrones y trampas

  • Cachear sin invalidación: fijar un TTL largo sin forma de purgar, para que un valor corregido permanezca equivocado durante horas.
  • Claves demasiado gruesas: cachear respuestas personalizadas bajo una clave compartida, filtrando datos de un usuario a otro.
  • Claves demasiado finas: incluir entradas volátiles en la clave para que ninguna dos peticiones coincida y la tasa de aciertos se derrumbe.
  • Sin protección contra la avalancha: una clave caliente expira bajo carga y cada petición arremete contra el origen a la vez.
  • Expiración sincronizada: un lote de entradas escritas juntas expira todas en el mismo instante sin jitter, provocando una horda periódica.
  • Cachear datos privados en capas compartidas: falta Cache-Control: private o no-store, y un proxy o CDN almacena respuestas autenticadas.
  • Ignorar entradas no claveadas: reflejar una cabecera en el cuerpo de la respuesta pero omitirla de la clave, abriendo la puerta al envenenamiento de caché.
  • Caché subdimensionado: un caché demasiado pequeño para el conjunto de trabajo sufre thrashing y expulsa entradas justo antes de que se necesiten.
  • Caché no medido: sin métrica de aciertos ni de expulsión, de modo que un caché que se deteriora es invisible hasta que se convierte en una caída.
  • Write-back sin durabilidad: escrituras rápidas que se evaporan cuando el caché muere antes de descargar, sin garantía de respaldo.

Modelo de madurez

  • Nivel 1, Iniciar: El caché es ad hoc y por desarrollador, añadido reactivamente cuando algo parece lento. Los TTLs son adivinados, las claves son inconsistentes, la invalidación es manual o inexistente, y los datos obsoletos y los misteriosos fallos son comunes. Nadie rastrea la tasa de aciertos, y un pico de tráfico que un caché debería haber absorbido en su lugar provoca una caída.
  • Nivel 2, Desarrollar: Los equipos cachéan en lugares obvios y usan una CDN para recursos estáticos. Aparecen TTLs básicos y cache-aside, pero las convenciones varían de un servicio a otro, la invalidación es inconsistente, la protección contra avalancha está ausente, las reglas de caché privado frente a compartido son informales y la observabilidad se limita a revisiones puntuales ocasionales.
  • Nivel 3, Estandarizar: Una estrategia de caché está documentada y se aplica en toda la organización. Las claves están normalizadas, los TTLs siguen una clasificación de frescura compartida, la invalidación es basada en eventos donde importa, la protección contra avalancha y la semántica HTTP correcta son estándar, los datos privados nunca se cachéan en capas compartidas, y cada capa informa tasa de aciertos y expulsión a un flujo de observabilidad común.
  • Nivel 4, Gestionar: El caché se mide y controla frente a líneas base. Cada capa tiene tasas de acierto objetivo, presupuestos de obsolescencia y umbrales de expulsión, y los paneles alertan cuando la tasa de aciertos cae o la tasa de expulsión sube por encima de su línea base. Las defensas contra avalancha se prueban a escala pico, la reducción de carga al origen se cuantifica por caché, los TTLs y las políticas de expulsión se ajustan desde patrones de acceso medidos, y la configuración de caché se revisa como código sensible a la seguridad antes del lanzamiento.
  • Nivel 5, Orquestar: El caché se mejora de forma continua y se integra en toda la organización. La colocación, las claves y los TTLs se adaptan al tráfico cambiante, el cómputo de borde se usa donde merece la pena, la planificación de capacidad y los modelos de coste se nutren de métricas de caché, y las lecciones de los incidentes de un equipo alimentan las convenciones compartidas. La organización trata el caché como una capacidad diseñada, medida y adaptativa, no como un conjunto de soluciones locales.

Ideas para la discusión

  1. ¿Qué caché único de tu sistema, si se enfriara ahora mismo, pondría más en peligro a tu origen, y qué lo protege?
  2. ¿Para cada capa de tu jerarquía de caché, puedes nombrar su tasa de aciertos actual de memoria, y si no, qué te dice eso?
  3. ¿Dónde has convertido un problema de invalidación en un problema de nombramiento con claves versionadas, y dónde podrías todavía hacerlo?
  4. ¿Cuál de tus rutas de escritura usa cache-aside, write-through, write-back o write-around, y cada uno se eligió a propósito?
  5. Si un atacante controlara una cabecera de petición, ¿podría envenenar alguna respuesta cachéada que comparten tus usuarios?
  6. ¿Cómo sabrías, en cuestión de minutos, que tu tasa de aciertos había caído en silencio veinte puntos?

Ideas clave

  • El caché reduce latencia, carga y coste, y la jerarquía de caché (cliente, CDN y borde, proxy inverso, aplicación, base de datos) permite responder lo más arriba y lo más cerca que puedas de forma segura.
  • La invalidación es la parte difícil; diseña claves y TTL a propósito y convierte los problemas de invalidación en problemas de nombramiento con claves versionadas siempre que puedas.
  • Protege el caché bajo carga con agrupación de peticiones, jitter y stale-while-revalidate, porque un caché se necesita más precisamente cuando una avalancha podría romperlo.
  • Elige patrones de escritura y políticas de expulsión por carga de trabajo, y usa la semántica HTTP de caché (Cache-Control, ETags, validación) de forma explícita en lugar de dejar que los cachés adivinen.
  • Trata el contenido en caché como superficie de ataque y mide tasa de aciertos, expulsión y obsolescencia, porque un caché no observado o mal claveado es un pasivo oculto, no un activo.

Referencias y lecturas adicionales

  • Martin Kleppmann, Designing Data-Intensive Applications
  • Andrew S. Tanenbaum y Herbert Bos, Modern Operating Systems
  • John L. Hennessy y David A. Patterson, Computer Architecture: A Quantitative Approach
  • Roy T. Fielding y Julian Reschke, «Hypertext Transfer Protocol (HTTP/1.1): Caching», RFC 7234, IETF
  • Mark Nottingham, «Caching Tutorial for Web Authors and Webmasters»
  • James Kettle, «Practical Web Cache Poisoning», PortSwigger Research
  • Betsy Beyer, Chris Jones, Jennifer Petoff y Niall Richard Murphy (eds.), Site Reliability Engineering: How Google Runs Production Systems
  • Michael T. Nygard, Release It! Design and Deploy Production-Ready Software