Cachear disponibilidad: el problema difícil de los motores de reservas
En un motor de disponibilidad, cachear mal es peor que no cachear. Cómo elegir la unidad de caché, qué invalidar y por qué el objetivo real es dejar de hacer trabajo.
Una consulta de disponibilidad parece una pregunta simple —¿hay sitio el día 12?— y no lo es. Es una pregunta que se abre en abanico: por producto, por fecha, por número de personas, por condiciones de cada proveedor. Y cada rama de ese abanico puede requerir hablar con un sistema externo que ni es rápido ni es tuyo.
Cuando ese abanico se multiplica por el volumen de consultas de una plataforma en hora punta, el problema deja de ser de lógica y pasa a ser de aritmética.
Por qué cachear la respuesta completa no funciona
El primer instinto es cachear el resultado final de la búsqueda: misma consulta, misma respuesta. Es fácil de implementar y produce una demostración excelente.
El problema aparece en producción, cuando descubres que casi ninguna consulta es idéntica a otra. Cambia un día, cambia el número de personas, cambia un filtro. Cada variación es una clave de caché distinta, así que el ratio de acierto se desploma. Acabas con una caché enorme, cara de mantener, que casi nunca acierta.
Peor todavía: cuando algo cambia, no sabes qué entradas invalidar, porque la relación entre un dato que ha cambiado y las respuestas que lo contienen es difusa. La salida fácil es poner un TTL corto, y entonces la caché deja de servir para lo que la pusiste.
Cachear la unidad, no la respuesta
El cambio de enfoque que sí funciona es bajar el nivel: cachear la unidad mínima de disponibilidad —un producto, una fecha, un cupo— en lugar del resultado compuesto.
Eso tiene dos consecuencias importantes:
La reutilización se dispara. Dos búsquedas completamente distintas comparten muchas unidades. Alguien que busca del 10 al 15 y alguien que busca del 12 al 18 comparten cuatro días del mismo producto. Con caché de respuesta no comparten nada; con caché de unidad comparten casi todo.
La invalidación se vuelve precisa. Cuando un proveedor comunica que ha cambiado el cupo de un producto en una fecha, sabes exactamente qué entrada tirar. No tienes que elegir entre invalidar de más o vivir con datos rancios.
El coste es que la respuesta hay que componerla en cada petición. Pero componer en memoria es barato; ir a buscar los datos es lo caro.
No toda la disponibilidad vale lo mismo
Una observación que cambia bastante las cosas: la distribución de consultas es profundamente desigual. Hay combinaciones de producto y fecha que se consultan cientos de veces por minuto y otras que no se consultan nunca.
Eso justifica tratarlas de forma distinta:
- Lo muy consultado conviene mantenerlo caliente de forma proactiva, refrescándolo en segundo plano antes de que caduque, para que ningún usuario pague nunca el coste de ir a buscarlo.
- Lo poco consultado puede resolverse de forma perezosa. No merece la pena mantener caliente algo que nadie va a pedir.
Intentar aplicar la misma política a todo lleva o a malgastar recursos refrescando lo que no interesa, o a dejar sin cubrir justo lo que más se pide.
El objetivo real: dejar de hacer trabajo
La conclusión que más me ha servido de trabajar en esto es que la caché es un medio, no el fin. El fin es no ejecutar trabajo innecesario, y la caché es solo una de las formas de lograrlo. Muchas veces hay otras más baratas:
- Descartar pronto. Si una combinación es imposible por reglas de negocio —fechas fuera de temporada, capacidad insuficiente—, comprobarlo antes evita todo el trabajo posterior. Un descarte temprano vale más que un acierto de caché, porque ni siquiera consulta.
- Agrupar. Si hay que preguntar a un proveedor por cinco productos, una llamada con cinco elementos casi siempre es mejor que cinco llamadas.
- No recalcular lo que no ha cambiado. Buena parte de las peticiones piden lo mismo que hace un segundo.
Cuando medí de verdad dónde se iba el tiempo, la mejora grande no vino de hacer las consultas más rápidas. Vino de darse cuenta de cuántas no hacían falta.
Datos rancios: decisión de negocio, no técnica
Toda caché de disponibilidad convive con la posibilidad de mostrar algo que ya no está.
La pregunta correcta no es «¿cómo evito esto por completo?» —no puedes, salvo que renuncies a cachear— sino «¿cuánto desfase es aceptable, y qué hacemos cuando ocurre?». Esa respuesta no la da la ingeniería: la da negocio. Lo que sí es responsabilidad técnica es que el sistema falle bien en ese caso: detectar el conflicto en el momento de confirmar y comunicarlo con claridad, en lugar de dejar una reserva en un estado ambiguo.
Un motor de disponibilidad que nunca muestra datos rancios y va lento pierde ventas. Uno que va rápido y gestiona mal los conflictos pierde confianza. El equilibrio está en el medio, y es una decisión que se toma explícitamente o se toma sola.