Ya os contamos qué son las mallas/mesh, cuáles son sus estructuras, topologías y arquitecturas que forman los sistemas y aplicaciones. Ahora, toca hablar sobre la arquitectura de microservicios y el papel de la estructura de mallas en esta arquitectura.
Este es un estilo arquitectónico distribuido que desde hace unos años se utiliza de forma primordial junto con tecnologías como Docker y Kubernetes, tanto on-premise como en cloud con servidor o sin servidor. Bien utilizado, puede ofrecer un diseño y características de las aplicaciones en cuanto a seguridad, escalabilidad, resiliencia y autonomía.
Los microservicios exponen las capacidades empresariales que se encapsulan a través de uno o más puntos endpoints, servicios. Además, se despliegan de manera independiente y se modelan en torno a un dominio empresarial. Se comunican entre sí a través de redes y, como opción de arquitectura, ofrecen muchas opciones para resolver los problemas a los que se pueden enfrentar.
Por lo tanto, una arquitectura de microservicios se basa en la colaboración de múltiples microservicios entre sí, a través de redes y diferentes protocolos de comunicación, que convierte los sistemas basados en ellos en sistemas distribuidos.
Los microservicios tiene en su ADN:
- Arquitectura orientada a los servicios (SOA).
- Se utiliza DDD sobre cómo deben trazarse los límites de estos.
- La capacidad de despliegue independiente es clave.
- Son agnósticos desde el punto de vista tecnológico.
Los microservicios encapsulan el almacenamiento y la recuperación de datos, exponiéndolos a través de interfaces bien definidas. Por lo tanto, las bases de datos están ocultas dentro de los límites de los microservicios.
Los microservicios se definen por su:
- Orientación al negocio: uno de los conceptos clave de la arquitectura de microservicios es que el servicio debe diseñarse en función de las capacidades del negocio, de modo que un servicio determinado sirva para un propósito específico del negocio y tenga un conjunto bien definido de responsabilidades. Un servicio determinado debe centrarse en hacer una sola cosa y hacerla bien. El tamaño del servicio nunca se determina en función del número de líneas de código o del número de personas que trabajan en ese servicio. Los conceptos como el Principio de responsabilidad (SRP), Event Storming, la ley de Conway, la aplicación de doce factores, el diseño dirigido por el dominio (DDD), etc., son útiles para identificar y diseñar el alcance y las funcionalidades de un microservicio.
- Autonomía: desarrollar, desplegar y escalar de forma independiente. Disponer de servicios autónomos podría ser el motor más importante para la realización de la arquitectura de microservicios. Los microservicios se desarrollan, despliegan y escalan como entidades independientes. A diferencia de los servicios web o de una arquitectura de aplicación monolítica, los servicios no comparten el mismo espacio de ejecución. Más bien se despliegan como tiempos de ejecución aislados aprovechando tecnologías como los contenedores. El éxito y la creciente adaptación de los contenedores y las tecnologías de gestión de contenedores como Docker, Kubernetes, Meso … es crucial para la realización de la autonomía de los servicios y contribuyen al éxito de la arquitectura de microservicios en su conjunto.
- Tolerancia a los fallos: los microservicios son más propensos a los fallos debido a la proliferación de los servicios y sus comunicaciones de red entre servicios. Una aplicación de microservicios determinada es una colección de servicios de grano fino y, por lo tanto, un fallo de uno o más de esos servicios no debería hacer caer toda la aplicación. En consecuencia, se debe manejar con eficacia el fallo dado de un microservicio para que tenga un impacto mínimo en las funcionalidades de negocio de la aplicación. El diseño de microservicios de forma tolerante a fallos requiere la adaptación de las tecnologías necesarias desde las fases de diseño, desarrollo y despliegue.
- Gestión de datos descentralizada: en una arquitectura monolítica, la aplicación almacena los datos en bases de datos lógicas únicas y centralizadas para implementar varias funcionalidades/capacidades de la aplicación. En una arquitectura de microservicios las funcionalidades están dispersas en múltiples microservicios. Si se utiliza la misma base de datos centralizada, los microservicios dejarán de ser independientes entre sí (por ejemplo, si un microservicio cambia el esquema de la base de datos, eso romperá varios otros servicios). Por lo tanto, cada microservicio debe tener su propia base de datos y su propio esquema de base de datos. Cada microservicio puede tener una base de datos privada para persistir los datos que requiere la implementación de la funcionalidad de negocio que ofrece. Un microservicio dado solo puede acceder a la base de datos privada dedicada y no a las bases de datos de otros microservicios.
- Gobierno de los servicios: el gobierno en los microservicios se interpreta como un proceso descentralizado, que permite a cada equipo/entidad gobernar su propio dominio como prefiera. El gobierno descentralizado es aplicable al proceso de desarrollo, despliegue y ejecución del servicio, pero hay mucho más que eso. Se pueden identificar dos aspectos clave del gobierno: el gobierno en tiempo de diseño de los servicios (selección de tecnologías, protocolos, etc.) y el gobierno en tiempo de ejecución (definiciones de servicios, registro y descubrimiento de servicios, versión de servicios…).
- El gobierno en tiempo de diseño en los microservicios es, sobre todo, un proceso descentralizado en el que cada propietario del microservicio tiene libertad para diseñar, desarrollar y ejecutar sus servicios.
- En el gobierno en tiempo de ejecución se pueden utilizar herramientas, en lugar de estandarizar en una única plataforma tecnológica. La implementación del gobierno en tiempo de ejecución se hace a menudo como un componente centralizado para aspectos como: necesidad de descubrir los endpoints de servicio, QoS (calidad de servicio), seguridad, circuit breaker de forma centralizada o versionado de servicios.
Como muchas cosas en la vida, las elecciones tienen un trade-off donde hay que medir los beneficios y peajes que tenemos que pagar para tomar una decisión; aunque algunos de los peajes que se tienen que pagar se podrán ir paliando con las diferentes mallas: servicios, eventos y datos.
Estos son algunos beneficios por lo que esta arquitectura ha ido creciendo en adeptos durante los últimos años:
- Desarrollo ágil y rápido de funcionalidades de negocio: la arquitectura de microservicios favorece el desarrollo de servicios autónomos, lo que ayuda a un desarrollo ágil y rápido de las funcionalidades de negocio. Con el desarrollo de servicios autónomos, solo hay que centrarse en la interfaz y la funcionalidad del servicio. Ya no nos centramos en la funcionalidad de todo el sistema, que es mucho más compleja, ya que todos los demás servicios se comunican a través de las llamadas de red mediante interfaces de servicio.
- Sustituibilidad: debido a su naturaleza autónoma, los microservicios también son reemplazables. Se construyen servicios como una entidad independiente, comunicándose a través de llamadas de red y APIs definidas, que se puede reemplazar fácilmente esa funcionalidad con otra mejor implementación. Estar centrado en una funcionalidad específica, tener un alcance y un tamaño limitados, y desplegarlo en un tiempo de ejecución independiente, hacen que sea mucho más fácil construir un servicio reemplazable.
- Aislamiento de fallos y previsibilidad: la reemplazabilidad también nos ayuda a conseguir el aislamiento y la predicción de fallos. Como se ha comentado, una aplicación basada en microservicios no puede explotar como una aplicación monolítica convencional debido al fallo de un componente o servicio determinado. Tener características de observabilidad adecuadas también nos ayuda a identificar o predecir posibles fallos.
- Despliegue ágil y escalabilidad: la facilidad de despliegue y escalado podría ser la propuesta de valor más importante de los microservicios. Con las modernas infraestructuras nativas de contenedores basadas en la nube, la capacidad de desplegar fácilmente un servicio y escalar dinámicamente se está convirtiendo en algo trivial. Se construyen capacidades como servicios autónomos, se puede aprovechar fácilmente todas estas tecnologías de contenedores y nativas de la nube para facilitar el despliegue ágil y la escalabilidad.
- Alineación con la estructura organizativa: dado que los microservicios están orientados a la capacidad de negocio, pueden alinearse bien con la estructura organizativa/de equipo. A menudo, una organización determinada está estructurada de manera que ofrece las capacidades de negocio. Por lo tanto, la propiedad de cada servicio se puede aplicar fácilmente a los equipos que poseen la funcionalidad del negocio. En consecuencia, dado que un microservicio se centra en una funcionalidad empresarial específica, se puede elegir un equipo relativamente pequeño para que sea el propietario de ese microservicio. Esto tiene un impacto positivo en el equipo de desarrollo, porque el alcance de un servicio determinado es simple y está bien definido. De este modo, el equipo puede hacerse cargo de todo el ciclo de vida del servicio.
La mayoría de los inconvenientes de la arquitectura de microservicios se deben principalmente a la proliferación de servicios a los que hay que hacer frente.
- Comunicación entre servicios: la complejidad de la comunicación entre servicios podría ser posiblemente más desafiante que la implementación de los servicios reales. La lógica de la comunicación entre los endpoints de los microservicios pasa a formar parte de nuestros microservicios en el desarrollo de las aplicaciones. Los desarrolladores de servicios tienen que dedicar una cantidad de tiempo considerable a la conexión de los microservicios para crear una funcionalidad completa consumible por usuarios o terceras partes.
- Monolito distribuido: con la arquitectura de microservicios, si no diseñamos bien los microservicios tendremos un nuevo monolito, pero distribuido. Esto significa que tendremos más problemas que con el monolito sin distribuir, puesto que tendremos mayores complicaciones al tener diferentes bases de datos, micro frontends que integrar… Para evitar tener un monolito distribuido, hay que asegurar que el diseño de los microservicios garantice la máxima autonomía de estos, es decir, acoplamiento débil de forma estática y dinámica. Un aliado para conseguir esta máxima autonomía la encontramos con las arquitecturas dirigidas por evento (Event Driven Architecture, EDA).
- Gobierno de los servicios: tener una serie de servicios comunicados a través de la red también complica el aspecto de gobierno y observabilidad de los servicios. Si no se dispone de las herramientas de gobierno y observabilidad adecuadas, será una pesadilla identificar las dependencias de los servicios y detectar los fallos. Por ejemplo, la gestión del ciclo de vida de los servicios, las pruebas, el descubrimiento, la supervisión, la calidad del servicio y otras capacidades de gobierno de los servicios serán más complejas con una arquitectura de microservicios.
- Depende en gran medida de las metodologías de despliegue: el éxito del despliegue y escalado de microservicios depende en gran medida de la adopción de contenedores y sistemas de orquestación de contenedores. Sin una infraestructura de este tipo, hay que invertir tiempo y energía en ella (y ni siquiera pienses en tener una arquitectura de microservicios exitosa sin contenedores).
El éxito de una arquitectura de microservicios también depende de los equipos y las personas. La propiedad de los servicios, pensar en hacer que los servicios sean ligeros y nativos de los contenedores, no tener un punto central para la gestión de los servicios nativos o no tener un punto central para integrar los servicios requieren cambios de cultura.
- Complejidad de la gestión de datos y transacciones distribuidas: dado que una arquitectura de microservicios promueve la localización de los datos a un servicio determinado, la gestión de datos distribuidos es más compleja. Lo mismo ocurre con las transacciones distribuidas: implementar los límites de las transacciones, y sus compensaciones, que se extienden a través de múltiples microservicios, es una dificultad añadida y compleja. Esto nos lleva a tener que tratar con determinados aspectos como la consistencia eventual, orquestación y/o coreografía de los microservicios.
Determinadas funciones empresariales que son consumidas por diferentes frontends (mobile, web…) o interfaces con terceros necesitan de la cooperación entre diferentes microservicios donde la reside la lógica de negocio y se aseguran la transaccionalidad de esta.
La cooperación entre los diferentes servicios se realiza de forma síncrona (el servicio invocante se queda bloqueado hasta recibir la respuesta) o asíncrona (no existe bloqueo). Simplificando todo mucho:
- En la cooperación síncrona se utilizan el patrón comando con diferentes protocolos, donde se mantiene la conexión hasta la finalización del servicio invocado que devuelve el control (REST, gRPC…).
- Sin embargo, en la comunicación asíncrona el control se devuelve de manera inmediata después de invocar el servicio (sin esperar su terminación) o enviar eventos.
Toda esta comunicación es a través de mensajes encapsulados, diferentes protocolos, TCP, UDP, HTTP, MQTT … De esta forma, se tienen dos posibles patrones arquitectónicos Service-Oriented architecture (Imperative/Functional Programming) o Event-Driven architecture (EDA) (Reactive Programming).
Estos dos patrones de arquitectura no son incompatibles. Es más, en la definición de la arquitectura de los sistemas es conveniente emplear ambos en los casos de uso, funcionales o técnicos, que se adecuen mejor.
Con la arquitectura basada en microservicios, es decir, la descomposición de las aplicaciones en diferentes funciones acotadas (dominnios o bounded contexts en el ámbito DDD) que trabajan juntas para lograr las funcionalidades de las aplicaciones. Los microservicios prometen ser más fáciles de codificar, probar y actualizar individualmente que las funciones integradas en aplicaciones monolíticas. Dicho esto, son difíciles de gestionar a escala empresarial porque las funciones relacionadas, que antes eran gestionadas por una aplicación que se ejecutaba en un host, ahora son gestionadas por una colección de microservicios distribuidos que se ejecutan en diversos entornos, incluyendo la nube y el borde. Esto introduce retos en áreas como la seguridad, el escalado, la red, la gestión de fallos y la orquestación de procesos.
Hay dos grandes capas de infraestructura que proporcionan capacidades que ayudan a los desarrolladores a centrarse en la lógica de negocio principal de los microservicios (en lugar de lidiar con las complicaciones de hacerlos interactuar): la malla de servicios y la malla de eventos.
Event Mesh y Service Mesh resuelven problemas que se originan en el mismo espacio de problemas, pero no responden a las mismas preguntas. Ambos patrones tienen en común que pueden volverse relevantes cuando la arquitectura de un sistema está creciendo y es necesario conectar más sistemas y servicios.
Estas capacidades son necesarias para apoyar el desarrollo de aplicaciones escalables y resilientes. Los microservicios y las arquitecturas en la nube a menudo aprovechan una malla de servicios, que es una infraestructura de red que gestiona la lógica de la red, permitiendo que el microservicio se centre en la lógica del negocio. Una malla de servicios admite el procesamiento síncrono de solicitudes y respuestas. Del mismo modo, una malla de eventos ayuda a los desarrolladores de aplicaciones a aliviar las preocupaciones sobre la ubicación de los consumidores en topologías distribuidas locales, regionales y globales para soportar casos de uso impulsados por eventos poco acoplados.
Por otra parte, se tiene otra capa funcional, la malla de datos, para el consumo de datos analíticos. Esta malla da opción a ir desmontando los supernodos de datos: Data warehouse, Data Lake, LakeHouse… con todas sus complicaciones inherentes (calidad, disponibilidad, accesibilidad) para el consumo analítico de datos. La malla de datos está compuesta de servicios que ofrecen por cada microservicio sus datos analíticos a los diferentes consumidores de estos, otros microservicios, herramientas o usuarios finales.
En este post hemos repasado los principales puntos de la arquitectura de microservicios y el papel de la estructura de mallas. Hemos visto los trade-offs en la arquitectura de microservicios, sus beneficios y peajes o cómo se comunican y coordinan.
Pero aún hay más. Este artículo forma parte de una serie en la que profundizamos en la definición de las mallas y hablamos sobre cómo nos ayudan las mallas de servicio (services mesh).
¿Tienes alguna duda? ¡Déjanos un comentario!
Cuéntanos qué te parece.