Almacenamiento de datos en caché externo: Redis en acción.

Federico Castellari
Another Integration Blog
6 min readApr 22, 2024

Introducción

Este artículo tiene como objetivo ejemplificar cómo implementar el almacenamiento en caché externo con una aplicación Mule y Redis.
El almacenamiento en caché es un tema muy amplio y, dependiendo el caso de uso, tendrá un enfoque diferente donde se deberán considerar varios aspectos, como la propiedad de los datos, asegurarse de que la memoria caché esté actualizada, la replicación, el rendimiento, la confiabilidad, la alta disponibilidad, y la escalabilidad.

¿Para qué almacenar en caché?
Muchas veces nos encontramos con bases de datos legadas o servicios que necesitamos consumir y exponer sus datos en tiempo real y éstos demoran mucho tiempo en responder ya sea por que el servicio es antiguo y sin mantenimiento, problemas de conectividad, o porque lo que estamos consultando es muy pesado.
Para hacer frente a esta limitación de los servicios legados, utilizamos, siempre y cuando no afectemos la fiabilidad y actualización de los datos, el almacenamiento en caché.
MuleSoft nos permite realizarlo tanto dentro de la aplicación (cliente) como también por política dentro de API Manager (servidor). En este caso vamos a ver como realizarlo dentro de la aplicación, ya sea implementando una estrategia global — almacenando los datos en un Object Store — o local — con un cache-scope.

Comparación entre un caché hit y un caché miss

La diferencia fundamental entre un cache hit (acierto de caché) y un cache miss (omisión de caché) radica en la ubicación de los datos en el momento de la solicitud. En un cache hit, los datos solicitados se encuentran en la caché, lo que permite una rápida recuperación de datos. En contraste, un cache miss significa que los datos no están en la caché en el momento de la solicitud, lo que requiere una recuperación más lenta desde la memoria principal o otra caché de nivel inferior.

La tasa de cache hits y cache misses impacta significativamente en el rendimiento del sistema. Una alta tasa de cache hits significa que la mayoría de las solicitudes de datos son satisfechas por la caché, lo que conduce a un acceso más rápido a los datos y a una mejora en el rendimiento. Por el contrario, una alta tasa de cache misses implica que muchas solicitudes de datos deben ser atendidas por jerarquías de memoria más lentas, lo que resulta en un rendimiento disminuido.
Para más información pueden visitar https://redis.io/glossary/cache-miss/.r

Acerca de Redis
Redis es una potente y versátil base de datos en memoria que se destaca por su velocidad y su capacidad para manejar una amplia gama de casos de uso, desde el almacenamiento en caché hasta la mensajería en tiempo real. Su estructura de datos en memoria y su arquitectura basada en clave-valor lo convierten en una opción popular para aplicaciones que requieren un acceso rápido a los datos.

Caso de Uso

Imaginemos que tenemos un servicio que necesita consultar las órdenes de compra en tiempo casi real y las órdenes están alojadas en una base datos legada que, además de tener problemas de conectividad demora mucho en su respuesta. Las órdenes son actualizadas, como mínimo, cada 3 horas. Un punto importante, es que nuestra aplicación no va a ser desplegada en CloudHub.

Vamos a ver cómo utilizando Redis podemos externalizar el almacenamiento en caché, utilizando para este caso un patrón de “cache hit and cache miss”.

Solución

Pre requisitos
Instalación de Redis
Puede ser una instalación local o cloud. En mi caso utilice la imagen de docker https://hub.docker.com/_/redis/#!#.
Les dejo los archivos de configuración para poder levantarlo con docker compose.
.Dockerfile:

FROM redis
COPY redis.conf /usr/local/etc/redis/redis.conf
CMD [ “redis-server”, “/usr/local/etc/redis/redis.conf” ]

redis.conf:

# Use a specific port (default is 6379)
port 6379
# Enable data persistence
save 900 1
save 300 10
save 60 10000
# Set the maximum memory limit
maxmemory 1GB
maxmemory-policy allkeys-lru

docker-compose.yml

version: '3'

services:
redis:
image: redis
container_name: redis-cache
ports:
- "6379:6379"
volumes:
- ./redis_data:/data

Con estos 3 archivos (.Dockerfile, redis.conf y docker.compose.yml) ubicados en la misma carpeta, nos posicionamos sobre la misma y ejecutamos:

docker-compose build
docker-compose up -d

Instalación RedisInsight (opcional)
RedisInsight es una herramienta para visualizar y optimizar los datos de Redis. Proporciona una interfaz de usuario intuitiva y eficiente para Redis y Redis Stack y admite la interacción CLI en un cliente de interfaz de usuario de escritorio con todas las funciones. Puedes descargarlo aquí.

Implementación
En Anypoint Studio, creamos un endpoint para escuchar las peticiones de consulta a las órdenes. Para este ejemplo también le pasamos el queryParam ‘tipoCache’ para determinar si vamos a probar por Redis o por Object Store. Para invocar la API podemos hacerlo con la siguiente url: http://localhost:8081/cache/ordenes/{idOrden}?tipoCache=redis.

Flujo para obtener la órden por Id
Configuración de conexión con Redis

Luego ruteamos dependiendo del tipoCache que puede ir para el subflujo de redis u object store. En este artículo sólo veremos Redis.

Global caché — flujo redis-cache
Antes de comenzar, agregamos el módulo Redis y creamos la configuración con los datos de conexión configurados en la instalación (https://docs.mulesoft.com/redis-connector/latest/redis-connector-reference).
Es importante en este punto configurar correctamente el ‘Entry ttl’ que es el tiempo en que la clave va a permanecer almacenada en Redis (en milisegundos). Una vez expirado el tiempo, la clave y su valor ya no estarán disponibles.

En este flujo implementamos la estrategia de caché “hit or miss” que, ante una consulta por el id de órden, buscamos en Redis la existencia de la clave(idOrden) y si existe, obtenemos el valor almacenado en caché. Si no existe, entonces simulamos una llamada al servicio backend que obtiene la órden y almacenamos la clave y valor.

flujo redis-cache

La Key utilizada para buscar y almacenar valores es el id de órden guardada al principio del flujo principal, que viene por uriParam.

Veamos algunos casos:

Iniciamos con Redis en estado Cold Cache (sin ninguna clave en caché).
Ejecutamos la siguiente petición al servicio:

curl --location 'localhost:8081/cache/orders/AR001-0001987?tipoCache=redis'

Como la clave no se encuentra en caché, la búsqueda no arroja resultados y se consulta al mock del backend para buscar la órden y luego almacenarlos en Redis. El mock devuelve un simple JSON con el id de la órden ingresada.

Flujo mock de buscar órden en backend

La órden es almacenada en Redis:

Como podemos observar, la próxima vez que busquemos esa órden, no se realiza la consulta al backend sino que los datos son extraídos desde Redis.

Conclusión

Con Redis como caché externa, se garantiza un acceso ultrarrápido a los datos, reduciendo la latencia y mejorando el rendimiento. Al integrar Redis con MuleSoft, las operaciones de caché se gestionan de manera eficiente, permitiendo una implementación ágil y una escalabilidad sin problemas. En conjunto, esta combinación impulsa la eficiencia y la competitividad empresarial al simplificar el desarrollo y la gestión de integraciones complejas.

--

--