ICM / servicio / Arquitectura de microservicios

Arquitectura de microservicios

23 septiembre 2020 | Carlos Calvo

Hoy vamos a hablar de microservicios, palabra que seguramente lleves un tiempo escuchando si trabajas o eres aficionado al mundo del desarrollo de software. Hasta hace bien poco, la infraestructura de aplicaciones -hablamos de aplicaciones web- eran monolíticas. O, dicho de otro modo, todo el código ejecutable de la web corría en un único servidor o como un único proceso. Si bien es verdad que podíamos escalar horizontalmente para aumentar el número de servidores, lo que hacíamos realmente era duplicar la web al completo para que ésta fuese ejecutada en varios servidores. Generalmente, colocando un elemento que repartiese las peticiones entre todos los servidores.

Los microservicios

Con la llegada de los microservicios esto ha ido cambiando. Cada vez más, nos encontramos con desarrollos en los que se ha fragmentado la aplicación en decenas de diminutos trozos que se ejecutan de forma totalmente autónoma e independiente y que están simplificados al máximo. Estos “trozos” cubren una necesidad concreta y específica del total de funcionalidades de la aplicación. Se consigue, normalmente, utilizando el desarrollo de APIs. En ellas presentamos una interfaz con una serie de funcionalidades que en su ejecución pueden llamar a otros procesos invisibles a ojos del usuario, pudiendo desarrollar cada microservicio en un lenguaje diferente y bajo arquitecturas diferentes.

Además, otra ventaja es que, para una empresa de desarrollo, es más fácil incorporar nuevos programadores a este. Cuando un desarrollador se incorpora a un equipo que está desarrollando una aplicación completa, éste se encuentra con la dificultad añadida de tener que aprender y entender mucho código antes de ser capaz de empezar a escribir el suyo propio. Pero con un desarrollo basado en microservicios, un nuevo desarrollador se encuentra con aplicaciones muy pequeñas -los trozos- que son fáciles de leer, entender y empezar a trabajar sobre ellos.

Aplicación basada en microservicios

Cuando nos disponemos a planear cómo será nuestra aplicación basada en microservicios sabemos que, al menos, deberíamos tener 3 aplicaciones totalmente diferenciadas:

  • Interfaz de usuario o UI.
  • Capa de negocio, lógica de la aplicación.
  • Capa de acceso a datos, si la aplicación debe acceder a base de datos.

Visto así, cualquiera podría decir que estos tres puntos se pueden comparar perfectamente con una aplicación MFC. Actualmente, Microsoft .NET Core o Microsoft .NET Framework ya permiten el desarrollo de aplicaciones en modo MVC. Aquí, las capas de negocio, UI y acceso a datos están claramente diferenciadas, pero no es exactamente lo mismo. Una cosa es cómo dividimos una aplicación, aun siendo todo el conjunto la misma aplicación. Y otra diferente, es generar aplicaciones diferentes y autónomas que juntas configuren nuestra aplicación al completo.

Ejemplo 1

Cuando la arquitectura de la aplicación está basada en microservicios, las diferentes partes de la aplicación se deben “hablar” entre ellas. Por ejemplo, supongamos un servicio al que, una vez registrado un usuario en nuestra app, éste deba recibir un mail de confirmación.

Con microservicios, debemos encontrar una fórmula para que cuando en un fragmento de la aplicación se produce un evento dado, la otra parte sea capaz de capturar ese evento. El microservicio que notifica por mail, tiene que haberse “dado cuenta” que se ha registrado un nuevo usuario.

Si no queremos hacer que nuestros microservicios se ejecuten de forma recurrente para comprobar si hay datos que procesar, podemos usar mecanismos de comunicación basados en eventos o en colas para hacer que nuestros fragmentos de código se “hablen”. Lo más típico es usar gestores de colas como RabbitMQ. O, si tenemos nuestra aplicación en la nube de Microsoft, podemos usar Microsoft Azure Service Bus. De este modo, el alta del nuevo usuario generará un evento que llegará a otro módulo de la aplicación, que reaccionará como haya sido diseñada a dicho evento. En nuestro caso, enviando un mail de bienvenida al usuario.

Ejemplo 2

Podemos usar este mismo ejemplo para imaginar que nuestra aplicación tiene un éxito brutal y que tenemos una media de 1000 nuevos registros por hora. Si nuestro microservicio dedicado a enviar correos se queda corto para el volumen de peticiones que recibe, podemos escalar nuestra aplicación haciendo crecer sólo la capacidad de procesamiento del módulo de envío de mails, dejando el resto igual.

Del mismo modo, tendremos una agilidad y unos tiempos de actuación ante incidencias muy bueno. Si, por ejemplo, el módulo de envío de mails está fallando, nos será super fácil encontrar el error y resolverlo en un tiempo récord. Sobre todo si cada pequeño fragmento de nuestra aplicación deja unos logs bien estructurados y con la información de depuración necesaria. Si nos fallase ese mismo módulo de envío de mails en una aplicación con una arquitectura monolítica, deberemos corregir el problema y volver a publicar la aplicación al completo. Lo que ya no es viable para las grandes aplicaciones vigentes de hoy en día.

Ventajas de los microservicios

Por lo tanto, hasta ahora hemos visto las siguientes ventajas:

  • Modularidad: al tratarse de servicios autónomos, se pueden desarrollar y desplegar de forma independiente. Además, un error en un fragmento concreto de la aplicación, no debería afectar la capacidad de otros fragmentos para seguir trabajando.
  • Escalabilidad: como es una aplicación modular, se puede escalar horizontalmente cada parte según sea necesario, se puede distribuir geográficamente en función de las necesidades, aumentando el escalado de los módulos que tengan un procesamiento más intensivo como comentábamos anteriormente.
  • Versatilidad: asimismo, cada parte de la aplicación puede ser escrita en un lenguaje de programación diferente, dependiendo de las necesidades concretas de cada microservicio.
  • Mantenimiento simple y barato: al poder hacerse mejoras de un solo módulo y no tener que intervenir en toda la estructura, el mantenimiento es más sencillo y barato que en otras arquitecturas.
  • Agilidad: el desarrollo es más rápido al tratarse de trozos de código que realizan una tarea muy concreta. Además, algunas de esas funcionalidades a cubrir puede que ya estén desarrolladas. Por ejemplo, la autenticación, pudiendo evitarnos desarrollo de funcionalidades que ya están desarrolladas por un tercero, como por ejemplo el módulo de autenticación de Microsoft u Office365.

Conclusión

Y nos dejamos un tema que quizás daría para otro post; contenedores. Es importante destacar que las arquitecturas de aplicaciones basadas en microservicios son perfectas para su implementación en entornos con contenedores como K8s -Kubernetes- o cualquier otra tecnología basada en contenedores.

Es verdad que cuando empezamos a desarrollar una aplicación cuesta un poco al principio visualizarla como un conjunto de “subaplicaciones” autónomas y que se ejecuten por separado. Pero claramente las tendencias de los últimos años parecen indicar que la arquitectura de los grandes proyectos irá por esos derroteros. Así que no dudéis en empezar a jugar con estas arquitecturas. Eso sí, para hacerlo bien, intentar también adquirir buenas capacidades con el gestor de contenedores que prefiráis. Teniendo en cuenta que si se usa Kubernetes, seguramente estés usando el gestor de contenedores que en el futuro predominará en el mercado.