Invalidación de caché — el proceso de eliminar o actualizar datos obsoletos en la caché para garantizar la relevancia de la información recibida por la aplicación. En el desarrollo móvil, la invalidación es críticamente importante: el usuario espera datos frescos sin una recarga completa. Según Google Developers, 2025, una invalidación correctamente configurada reduce las solicitudes de red en un 60% y mejora la capacidad de respuesta de la interfaz.
Puntos clave
Invalidación de caché es el proceso de invalidar o actualizar entradas en caché que ya no coinciden con el estado actual de la fuente de datos. A diferencia de limpiar manualmente toda la caché, la invalidación funciona de forma selectiva: solo los datos cuya relevancia está en duda.
La caché almacena copias de datos para un acceso rápido. Con el tiempo, los datos originales en la base de datos o en el servidor pueden cambiar — por ejemplo, un usuario actualizó su perfil o apareció una nueva publicación en el feed. Si la caché no se invalida, la aplicación mostrará información desactualizada, lo que en aplicaciones móviles provoca errores de transacción, visualización incorrecta y pérdida de confianza.
La principal dificultad de cualquier invalidación es el conocido dicho “There are only two hard things in Computer Science: cache invalidation and naming things”. La complejidad radica en que la caché no sabe cuándo la fuente ha cambiado a menos que se le notifique explícitamente.
Según Martin Kleppmann, autor de “Designing Data-Intensive Applications” (O’Reilly, 2017), una invalidación correcta requiere una notificación centralizada de los cambios o un mecanismo para verificar la relevancia en cada lectura — un compromiso entre rendimiento y consistencia.
data class CacheEntryT(
val data: T,
val expiresAt: Long,
val version: Int = 0
)
fun CacheT.isValid(key: String): Boolean =
get(key)?.let { it.expiresAt > currentTimeMillis() && it.version == currentVersion(key) } ?: false
Este código muestra un enfoque simple: una entrada en caché se considera válida si el TTL no ha expirado y la versión coincide con la actual en la fuente. El mecanismo de versionado es una de las formas fiables de evitar mostrar datos desactualizados.
Actualidad de los datos es un requisito clave para la mayoría de las aplicaciones móviles: redes sociales, mensajería, servicios bancarios, plataformas de comercio electrónico. Un usuario que ve un saldo de cuenta incorrecto o mensajes antiguos pierde la confianza en la aplicación.
Además de la experiencia del usuario, la invalidación ahorra tráfico y batería. En lugar de recargar periódicamente todos los datos, una aplicación móvil puede invalidar solo las entradas modificadas y cargarlas de forma selectiva. Según Meta Engineering (2024), la implementación de invalidación incremental en Facebook Lite redujo el consumo de tráfico en un 35% sin perder la actualidad del contenido.
Otro aspecto importante es la consistencia de las transacciones. En aplicaciones con carrito de compras o sistema de reservas, el uso de caché obsoleta puede provocar dobles cobros o conflictos de datos. La invalidación después de operaciones críticas garantiza que la siguiente solicitud lea datos frescos.
TTL es la estrategia más simple, donde cada entrada en caché recibe un tiempo de vida fijo. Cuando expira el TTL, los datos se consideran obsoletos y se eliminan en la siguiente lectura. TTL es ideal para datos que se actualizan según un horario — por ejemplo, el clima o los tipos de cambio. Inconveniente: los datos pueden estar desactualizados dentro del intervalo TTL.
Con la estrategia Write-Through, cada cambio de datos pasa por la caché: la escritura se realiza simultáneamente en la caché y en la fuente. Esto garantiza que la caché siempre contenga la versión actual. El inconveniente es una mayor latencia de escritura, ya que la operación no se completa hasta que la fuente confirma. Write-Through es adecuado para datos críticos para la consistencia: saldo de cuenta, estado del pedido.
Write-Behind es una escritura asíncrona: los datos van inmediatamente a la caché y se escriben en la fuente más tarde mediante un proceso separado. Esto proporciona un alto rendimiento de escritura pero conlleva el riesgo de pérdida de datos en caso de fallo antes de la sincronización. En aplicaciones móviles, Write-Behind se utiliza a menudo para análisis, registros y acciones de usuario no críticas.
Write-Invalidate — en lugar de actualizar la caché cuando los datos cambian, simplemente elimina (invalida) la entrada correspondiente. La siguiente lectura detectará un fallo de caché y cargará datos frescos desde la fuente. Esta estrategia es simple de implementar y funciona bien cuando las solicitudes de lectura superan significativamente a las de escritura.
| Estrategia | Rendimiento de lectura | Rendimiento de escritura | Consistencia |
|---|---|---|---|
| TTL | Alto | Alto | Débil (posible obsoleto) |
| Write-Through | Alto | Medio | Fuerte |
| Write-Behind | Alto | Alto | Débil (posible pérdida) |
| Write-Invalidate | Medio | Alto | Fuerte (en lectura posterior) |
La elección de la estrategia depende de lo que sea más importante para un escenario específico: velocidad de respuesta, consistencia o ahorro de recursos. Los enfoques híbridos — por ejemplo, TTL con Write-Invalidate al recibir una notificación push — proporcionan un equilibrio óptimo.
Caché HTTP es el primer nivel en el lado del cliente. El navegador o la aplicación móvil almacena las respuestas del servidor con los encabezados Cache-Control y ETag. La invalidación ocurre al recibir una respuesta 304 Not Modified o al expirar max-age. ETag permite al cliente verificar la actualidad del recurso sin descargar la respuesta completa.
Caché de la aplicación es el segundo nivel, gestionado por código: cachés en memoria (LRU, LruCache en Android) o en disco (SQLite, Room, Realm). La invalidación aquí la controla el desarrollador. Según Android Developers (2025), el uso correcto de Room con Flow y la invalidación basada en disparadores reduce los redibujados de la interfaz en un 40%.
Caché del servidor es el tercer nivel: Redis, Memcached, CDN. En este nivel, la invalidación se realiza mediante TTL, comandos DEL/PURGE o brokers de mensajes (RabbitMQ, Kafka). La invalidación de CDN es un desafío aparte: debido a la naturaleza distribuida de la CDN, un comando de purga puede tardar minutos en propagarse globalmente. Según Cloudflare (2024), la invalidación mediante Purge by URL tarda en promedio de 5 a 15 segundos para la propagación global.
Para coordinar la invalidación en todos los niveles se utiliza un servicio de caché centralizado o un broker de eventos. Cuando los datos cambian, la fuente publica un evento y cada nivel recibe una orden para invalidar claves específicas. Esto evita una situación en la que un nivel ya ha actualizado los datos mientras otro continúa sirviendo la versión obsoleta.
TTL demasiado largo es el error más común. Los desarrolladores establecen TTL con margen, lo que provoca que los usuarios vean datos desactualizados durante horas o días. Solución: comenzar con un TTL corto (1–5 minutos) y aumentarlo solo después de medir la necesidad real.
Invalidar toda la caché ante un solo cambio es un problema típico en la arquitectura de microservicios. Un usuario actualiza su avatar y la caché se invalida para todos. Con un gran número de usuarios, esto provoca un Cache Stampede — una avalancha de solicitudes a la fuente. Solución: invalidar solo la clave del usuario específico, no la caché compartida.
Falta de invalidación en errores de escritura — si la escritura en la fuente falla pero la caché ya se ha actualizado, la aplicación termina en un estado inconsistente. Solución: invalidación en dos fases — primero limpiar la caché, luego escribir en la fuente y revertir la invalidación en caso de error.
Ignorar la naturaleza distribuida — en un entorno en clúster, la invalidación en un nodo no significa que otros nodos hayan recibido la orden. Sin un broker de eventos, algunos servidores continuarán sirviendo datos obsoletos. Redis Pub/Sub o Apache Kafka resuelven este problema mediante la difusión de eventos de invalidación.
Determine los requisitos de actualidad — qué tan crítico es que los datos estén actualizados “en este momento.” Para un feed de noticias, un retraso de 1–2 minutos es aceptable (TTL). Para el saldo de una cuenta, el retraso es inaceptable (Write-Through).
Evalúe la frecuencia de cambios — los datos que se actualizan una vez al día (catálogo de productos, guía de ciudades) funcionan bien con TTL. Los datos que cambian decenas de veces por segundo (estados en línea, tipos de cambio) requieren invalidación push a través de WebSockets o Firebase Cloud Messaging.
Considere el costo de lectura de la fuente — si la fuente es una costosa consulta SQL en 10 tablas o una API externa con límites, use un almacenamiento en caché agresivo con un TTL largo, pero compense los datos obsoletos con invalidación push. Si la lectura es barata (búsqueda en memoria), use un TTL corto y Write-Invalidate.
Según Google I/O (2025), el patrón típico para aplicaciones móviles es Stale-While-Revalidate: el usuario ve instantáneamente los datos en caché mientras la aplicación verifica su actualidad en segundo plano y los actualiza. Esto combina velocidad de respuesta y actualidad sin compromisos. El encabezado HTTP Cache-Control con la directiva stale-while-revalidate es compatible desde Android 10 y iOS 13.
Preguntas frecuentes
Invalidación es marcar un registro específico como obsoleto, tras lo cual se actualiza en la siguiente lectura. La limpieza de caché es la eliminación completa de todas las entradas, lo que es más costoso y puede reducir temporalmente el rendimiento de la aplicación.
ETag es un hash o versión de un recurso que el servidor devuelve en un encabezado HTTP. En una solicitud repetida, el cliente envía If-None-Match con el ETag actual. Si el recurso no ha cambiado, el servidor responde con 304 Not Modified y la caché sigue siendo válida.
Write-Through con versionado es la más fiable, ya que los datos siempre son consistentes. Pero tiene la mayor latencia de escritura. En la práctica, se usa más a menudo TTL con invalidación push para equilibrar rendimiento y actualidad.
Use Probabilistic Early Expiration — cada solicitud verifica aleatoriamente la actualidad de la caché antes de que expire el TTL. El algoritmo XFetch (Vattani, 2015) calcula la probabilidad de recálculo mediante la fórmula: p = (ttl - age) / (ttl * beta).
Use herramientas de depuración de red: Charles Proxy, Proxyman o el Inspector de Red integrado en Android Studio y Xcode. Verifique que después de modificar los datos, la siguiente solicitud cargue realmente la nueva versión en lugar de devolver la almacenada en caché.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también