Cache, en una aplicación medianamente escalable, ni que
decir en una altamente escalable, la cache es un elemento clave en el desempeño
y tiempo de respuesta. Regularmente utilizamos la cache de una manera muy
simple, basado en un conjunto de entradas determinamos si el objeto se
encuentra en cache, si no se encuentra ejecutamos la lógica de negocios para
obtener la información y volver a introducirla en la cache para futuros llamados. Regularmente este esquema
es lo suficientemente bueno para la mayoría de sistemas de tamaño regular, pero
un sistema con muchas consultas, un nivel de concurrencia mayor, etc, debemos
empezar analizar el comportamiento de nuestra memoria y determinar las mejores
estrategias de almacenamiento cache.
Que cachear, supercache
En lo personal creo que una estrategia cache muy eficaz (sin
embargo no siempre eficiente) es almacenar a fuerza bruta si es posible toda la
información en memoria, es decir si tenemos un cluster de cache con memoria RAM
lo suficientemente grande como para que podamos guardar por ejemplo el catalogo de
productos, mi recomendación sería guardar todo ahí, sistemas como los de redes
sociales, suelen tener clusters gigantes con información guardada en memoria y
hace que las aplicaciones sean más rápidas, en este esquema por lo regular solo
tenemos que tener cuidado con la invalidación de la cache (cuando algo cachado
cambia, debe eliminarse el registro actual de la cache para que obtenga los últimos cambios). Podríamos
reducir entonces la estrategia a, si tiene mucho espacio en memoria,
simplemente úselo.
Los más populares
En algunos modelos de negocios conocemos cuales objetos son
los más populares, tanto por conteo estadísticos como heurísticas de negocio;
tomemos por ejemplo el caso de un sistema de comercio electrónico, un agente de
negocios puede conocer de antemano cuales productos son los más vendidos, más
populares, etc. Así pues con este conocimiento podríamos levantar un listado de
productos y al inicio de la aplicación hacer un “warm up” de la cache con estos
objetos, adicionalmente si no se tienen muchas áreas de cache yo recomiendo
crear estos objetos en un área aparte del resto de productos comúnmente
cachados con el fin de monitorear en el futuro el comportamiento de estos
objetos en cache.
La segunda estrategia siempre dentro del esquema de los más
populares es calcularla programáticamente mediante el análisis estadístico de
la cache (sencillo cuales productos pasan más tiempo en memoria a razón de
mayor cantidad de hits), así pues podemos guardar esta lista en algún mecanismo
de persistencia y cuando se requiera o cuando se inicia la aplicación solicitar
que se caliente la cache con estos elementos también.
Por último se me ocurre una tercera estrategia, esta de la
mano de la heurística; un producto nuevo puede de pronto volverse popular
(incluso uno impopular puede volverse popular), regularmente la gente de
marketing tiene métricas sobre sus expectativas de ventas, por ejemplo una
promoción (un producto nuevo), un sale (productos que se van a colocar en
oferta), un combo (grupo de productos a mejor precio), producto posicionado (un
producto que se va poner por ejemplo en la página de home page o alguna otra página
de alto alcance, etc). Estas acciones tienen un motivo claramente conocido por
marketing y en conjunto, se pueden crear listas de productos para ser cachados
previamente y así hacer la aplicación mas rápida y eficiente (cache implica
menos tiempo de CPU, I/O etc), ante la probabilidad de mayores consultas sobre
estos objetos.
Impopulares y filtros
Regularmente dependiendo de las facilidades de hardware con
que contamos (como dijimos antes si tiene mucha memoria y puede cacharlo todo,
simplemente hágalo), filtramos los objetos que vamos a introducir a memoria. La
estrategia más sencilla es limitar el tamaño de los objetos, por ejemplo nada mayor a 100kb o un
megabyte, etc. Esto con el motivo de no saturar nuestra cache con objetos
gigantes de manera muy rápida.
Si bien es cierto tener algo en cache ahorra tiempo de CPU y
regularmente I/O, latencia y por ende tiempo de respuesta al usuario, pero también
debemos tener en cuenta que si nuestro espacio de memoria para cache es
limitado debemos evitar incluir objetos que consumirán memoria en forma de
paracito, me explico; la idea de la cache es almacenar un objeto en ella, de
tal manera que reciba al menos un hit antes de que este expire y sea eliminado
de la cache (depende de la estrategia pero regularmente por prioridad o TTL, un
objeto es eliminado de la cache cuando no es invocado por mucho tiempo y la
cache está llena o cuando se vence un el tiempo designado en TTL), así pues
agregar objetos a la cache que nunca son leídos resultará en una mala gestión
de nuestros recursos de hardware.
Por ende, lo que se propone es identificar
que objetos son los más impopulares y filtrar su adicción a la cache, por
ejemplo los frameworks de cache regularmente proporcionan estadísticas acerca
del comportamientos de los entries, pero nosotros podemos hacer un servicio que
sea el helper mediante el cual se entra a la cache y guardar estadísticas propias
acerca de que objetos se llaman y hacen hit, cuales se llaman y no hacen hit y así
determinar cuáles son populares o no, o inclusive determinar si el tiempo de
TTL para un objeto debe ser mayor, por ejemplo si tenemos un TTL parejo de 10
minutos y ciertos objetos son invocados cada 15 minutos, entonces estos vivirán
10 minutos en cache, serán eliminados pasados esos 10 minutos, para que 5
minutos después sean agregados de nuevo en la cache de forma infortunada.
Así pues, tendríamos implementados sobre la capa de
abstracción de cache, una capa de estadísticas y otra de filtrado que nos ayude
a determinar el comportamiento de los objetos en la cache.
Como vemos, existen algunas alternativas para hacer que
nuestra estrategia de cache sea más asertiva y eficiente, mas adelante espero
presentar un diagrama de clases e implementaciones de cómo lograr algunas de
estas para que puedan darse una idea más clara de cómo implementarlas.
Pura vida,
J
Comentarios
http://www.naturaprint.es