Concrete Logo
Hamburger button

Utilizando Cache con Redis y Node.js

  • Blog
  • 18 de Junho de 2019
Share



En la actualidad existen varias APIs en Node.js que trabajan con mucho procesamiento, consulta en bases de datos relacionales y no relacionales, acceso en disco, servicios legados e incluso otras API. Diversos factores que generan tiempo de petición, banda y procesamiento nos dejan sujetos a estructuras que, si mal planificadas, pueden generar un caudal técnico en el futuro, exigiendo cambios en la arquitectura para mejorar el desempeño de la aplicación. Otras veces quedamos presos a servicios impuestos por el cliente y sus requisitos, lo que nos impide implementar algo más estructurado.

Cuando usted para percibir todos los detalles de su aplicación entiende que pueden existir procesos que se realizan varias veces y devuelven datos que no se cambian con tanta frecuencia. A cada solicitud hecha, como la lectura de un archivo, servicios de terceros o banco, caímos en una serie de factores que implican en tiempo, procesamiento y banda.

Una situación, por ejemplo, tendría que acceder a un archivo y devolverlo al usuario. En este caso, como ya se muestra en la literatura, la lectura de un archivo es lenta y depende de diversas condiciones, entre tiempo de Seek, cuán dispersado ese archivo está en su HD, entre otras.

Ahora, imagine otra situación. Su API necesita hacer una petición para cinco otros servicios que van desde una solicitud SOAP, consulta al banco, servicios de terceros y una búsqueda en el Elasticsearch. Suponiendo que cada petición tarda 1000ms, necesitaríamos un tiempo total de 5000ms para volver la petición.

En el caso de Node.js, podríamos utilizar algún paquete npm para que las peticiones fueran llamadas en paralelo. Sin embargo, si hago la misma solicitud varias veces en mi API y los datos de otros servicios no se cambian constantemente, nuestra aplicación realizará el mismo procedimiento varias veces.

¿No sería más fácil nuestra aplicación lograr identificar que esa solicitud ya fue hecha y devolver los datos guardados en algún lugar, sin la necesidad de realizar todo de nuevo?

Sí! Y podemos hacer esto de varias formas, pero el patrón más conocido es utilizando caché. El uso de la caché puede ir de extremo a extremo en nuestro sistema, ya sea en la capa del cliente, desde el servidor web hasta después, en la aplicación.

En la capa de cliente, como un navegador por ejemplo, se debe crear una forma capaz de recopilar estos datos y guardar en alguna API del navegador, como las más antiguas utilizando cookies o tecnologías un poco más nuevas como caché con servicio de trabajo, tecnología mucho utilizado actualmente con PWA.

En la capa del servidor web, en el caso de Ngnix se podría agregar el ETAG que ayudaría a identificar cuando hubo un cambio en esa petición y Expires / cache-control para tiempo de vida que puede ser utilizado aquel contenido.

En la capa de aplicación, podemos hacer un análisis más sucinto de los puntos que son posibles de ser cacheados y el tiempo de vida que cada petición externa puede tener, garantizando mejor la integridad de los datos que serán transferidos al cliente. Podemos almacenar la caché en la memoria o utilizar un servicio para ello.

PUNTOS NEGATIVOS

En la capa de cliente, incluso creando estructuras que guardan estos datos, sería como mínimo necesario crear una interfaz con la aplicación para identificar cuando los datos todavía se pueden utilizar. Además, poseemos varios tipos de clientes. Hablando sólo de Browser, tenemos los más antiguos, que son difíciles de depurar, navegadores de dispositivos móviles de versiones antiguas, además del soporte a las API que cada uno posee.

En la capa de servidor web podemos tener otro problema, como un control generalizado de caché. En un trabajo que participé teníamos scripts de recolección de datos en e-commerces de Brasil, pero cada vez que actualizamos ese script, que estaba guardado en los CDN de Akamai, tardaba alrededor de un día para ser propagado en todos los servidores, por cuenta de la caché. Si ocurría un error, en épocas como el Viernes Negro, por ejemplo, esto podría ser un problema gravísimo para la recolección de los datos que realizamos. Todo se perdería ese día.

En la capa de aplicación utilizar caché en memoria tampoco es una idea tan favorable, ya que una buena práctica es no guardar el estado de nada en la API (Stateless). Sería una complicación precisar escalar horizontalmente y conseguir mantener la integridad de esa caché.

REDIS

Una de las formas más robustas de tratar estos escollos es tener una calidad mejor en la caché, utilizando un servidor o servicio. El más común actualmente es Redis, que es una base de datos NoSQL de clave y valor. Según una encuesta realizada por RisingStack con más de mil desarrolladores, esta herramienta es adoptada por casi el 50% de los desarrolladores que trabajan con Node.js, lo que muestra su confianza en ese ecosistema.

Pero, ¿por qué no es necesario que Redis en lugar de Memcached, plataforma que ya lleva mucho tiempo en el mercado? Comparando los dos, ambos pueden realizar tareas de caché con alto rendimiento al asignar todo en la memoria, luego si se produce un problema y el servidor de memcached se reinicia, su caché se guardará en una memoria volátil. Con el redis el caso ya es diferente, pues tiene un flashback y lo guarda todo en disco. Al reiniciarse, su caché volverá normalme

Otro punto es si el Memcached no está aguantando la cantidad de datos asignados en la memoria, entonces será necesario aumentar el servidor verticalmente. Redis tiene la capacidad de trabajar con clúster de hasta mil nudos, creciendo tanto verticalmente como horizontalmente. Redis también trabaja con PUB / SUB. Por ejemplo, imagínese que tiene el servicio A que hace una llamada al microservicio B, el servicio A recibe los datos y luego se almacena en caché. En el caso de que el servicio B se actualiza, avisaría al servicio A que hubo un cambio y que sería necesario limpiar la caché con un canal de PUB / SUB. Todos los que estuvieran escritos en ese canal serían capaces de recibir ese mensaje y limpiar la caché.

El sitio oficial de Redis dice que es un banco Open-Source que tiene almacenamiento de estructura de datos en memoria y realiza persistencia en disco que puede ser utilizado también como fallback, en caso de que ocurra algún problema en el servidor. Tiene una estructura de clave y valor y puede guardar varios tipos de datos, desde una simple cadena, como hash, hasta números, lista y otros. Tiene la función de tiempo de vida para invalidar datos en un período de tiempo, además de soportar transacciones, oriundas de los bancos de datos relacionales, que respetan el ACID.

La encuesta mencionada anteriormente muestra que el 43% de los desarrolladores de Node.js no utilizan ninguna de las herramientas de caché citadas. Esto puede ser un indicio de que muchos desarrolladores no conocen herramientas de caché o creen que la complejidad de insertarlas en su stack puede comprometer el proyecto. Después de la explicación, vamos a crear una aplicación Node.js que consume una base de datos y la API de github que crea la caché con el Redis, todo dockerizado, lo que puede acceder a este enlace de github.

INSTALANDO DEPENDENCIAS

Este proyecto muestra un ejemplo en el que consultamos las organizaciones del github, guardaremos en la base de datos y volver a la consulta, si ya está en caché.

Son dos rutas:

  1. / orgs / {nombreDelOrganización} -> que devuelve datos de la organización;
  2. / orgs -> que devuelve todas las organizaciones que ya se han consultado.

BIBLIOTECA DE REDIS PARA INSTALAR

O

INICIO DEL PROYECTO

COMPROBAR SI LA CONEXIÓN DE PRODUJO CON ÉXITO

FUNCION PARA GUARDAR CACHE

  • KeyName -> chave na qual será salvo o valor;
  • value -> valor que será salvo, no geral pode ser string, inteiro ou objeto de primeira ordem;
  • timeInSecond -> tipo de temporizador que será utilizado;‘EX’ -> Tempo em segundos;
  • ‘PX’ -> Tempo em milisegundos;
  • ‘NX’ -> Inserir se não existir;
  • ‘EX’ -> Inserir se existir.

FUNCIÓN PARA GUARDAR DATOS DE CACHE

CREANDO UN MIDDLEWARE PARA EL EXPRESS

CREANDO UN CANAL DE PUB/SUB..

… con expres.js mongo redis que va a salvar.

Estos se ejecutar en dos escenarios, creando un middleware simple para comprobar si ya existe caché y devolver los datos. En otro paso vamos a separar la caché si es necesario y limpiar una clave a través de un canal de PUB / SUB.

Para subir las dependencias externas del proyecto, Redis y MongoDb, basta con utilizar este comando:

REFERENCIAS

¡Y es eso! ¿Ha quedado alguna duda o tiene algo que decir? Aproveche los campos abajo. ¡Hasta la próxima!

Es desarrollador JavaScript y quiere trabajar en un equipo ágil de verdad? Deja tu currículum en;
trabajeconnosotros@concrete.com.br