Guía de diseño de microservicios

Es 2018, todos han escuchado sobre Microservicios. ¿Pero sabes cómo diseñar uno?

Los microservicios son un tema de tendencia entre los ingenieros de software actuales. Comprendamos cómo podemos construir sistemas de TI ágiles para empresas y verdaderamente modulares con el estilo arquitectónico de Microservices.

Concepto de microservicios

La arquitectura de microservicios consiste en colecciones de servicios livianos y poco acoplados. Cada servicio implementa una capacidad comercial única. Idealmente, estos servicios deberían ser lo suficientemente coherentes como para desarrollar, probar, liberar, implementar, escalar, integrar y mantener de forma independiente.

Definicion formal
“El estilo arquitectónico de microservicios es un enfoque para desarrollar una sola aplicación como un conjunto de pequeños servicios, cada uno de los cuales se ejecuta en su propio proceso y se comunica con mecanismos ligeros, a menudo una API de recursos HTTP. Estos servicios se basan en las capacidades comerciales y se pueden implementar de forma independiente mediante maquinaria de implementación totalmente automatizada. Existe un mínimo de gestión centralizada de estos servicios, que pueden estar escritos en diferentes lenguajes de programación y utilizar diferentes tecnologías de almacenamiento de datos ".
- James Lewis y Martin Fowler

Características definitorias de microservicios

  • Cada servicio es una unidad de negocios ligera, independiente y poco acoplada.
  • Cada servicio tiene su propia base de código, administrada y desarrollada por un pequeño equipo (principalmente en un entorno ágil).
  • Cada servicio es responsable de una sola parte de la funcionalidad (capacidad comercial) y lo hace bien.
  • Cada servicio puede elegir la mejor pila de tecnología para sus casos de uso (no es necesario adherirse a un marco de trabajo en toda la aplicación).
  • Cada servicio tiene su propio plan DevOp (prueba, lanzamiento, implementación, escala, integración y mantenimiento de forma independiente).
  • Cada servicio se implementa en un entorno autónomo.
  • Los servicios se comunican entre sí mediante API bien definidas (puntos finales inteligentes) y protocolos simples como REST sobre HTTP (canalizaciones tontas).
  • Cada servicio es responsable de conservar sus propios datos y mantener el estado externo (solo si varios servicios consumen los mismos datos, tales situaciones se manejan en una capa de datos común).

Beneficios de los microservicios

Los microservicios están hechos para escalar grandes sistemas. También son excelentes habilitadores para la integración continua y la entrega.

The Scale Cube: modelo tridimensional para la escalabilidad (Imagen: Nginx Blog)
  • Escalado independiente: la arquitectura de Microservicios admite el concepto Scale Cube descrito en el excelente libro The Art of Scalability. Al desarrollar microservicios para lograr la descomposición funcional, la aplicación se escala automáticamente a través del eje Y. Cuando el consumo es alto, los microservicios pueden escalar a través del eje X clonando con más CPU y memoria. Para distribuir datos en varias máquinas, las bases de datos grandes se pueden separar (fragmentar) en partes más pequeñas, más rápidas y más fáciles de administrar, lo que permite el escalado del eje Z
  • Lanzamientos e implementaciones independientes: las correcciones de errores y los lanzamientos de funciones son más manejables y menos riesgosos, con microservicios. Puede actualizar un servicio sin volver a implementar toda la aplicación y retroceder o avanzar una actualización si algo sale mal.
  • Desarrollo independiente: cada servicio tiene su propia base de código, que es desarrollada, probada e implementada por un pequeño equipo enfocado. Los desarrolladores pueden centrarse en un servicio y un alcance relativamente pequeño solamente. Esto da como resultado una mayor productividad, velocidad del proyecto, innovación continua y calidad en origen.
  • Degradación elegante: si un servicio deja de funcionar, su impacto no se propagará al resto de la aplicación y resultará en una falla catastrófica del sistema, permitiendo que se manifieste un cierto grado de antifragilidad.
  • Gobierno descentralizado: los desarrolladores son libres de elegir las pilas de tecnología y tomar los estándares de diseño y las decisiones de implementación que mejor se adapten a su servicio. Los equipos no tienen que ser penalizados debido a decisiones tecnológicas pasadas.

Preocupaciones operacionales

Los servicios independientes por sí solos no pueden formar un sistema. Para el verdadero éxito de la arquitectura de microservicios, se requieren inversiones significativas para manejar problemas entre sistemas como:

  • Replicación de servicios: un mecanismo por el cual los servicios pueden escalar fácilmente según los metadatos
  • Registro y descubrimiento de servicios: un mecanismo que permite la búsqueda de servicios y encuentra el punto final para cada servicio
  • Monitoreo y registro de servicios: un mecanismo para agregar registros de diferentes microservicios y proporcionar informes consistentes
  • Resiliencia: un mecanismo para que los servicios tomen acciones correctivas automáticamente durante fallas
  • DevOps: un mecanismo para manejar la integración y la implementación continua (CI y CD)
  • API Gateway: un mecanismo para proporcionar un punto de entrada para los clientes

Middleware y Patrones de Diseño

API Gateway (punto de entrada único para todos los clientes)

Arquitectura de microservicios de estilo API Gateway (Imagen: Microsoft Azure Docs): este es el patrón de diseño más común utilizado en microservicios. API Gateway es un intermediario con capacidades de enrutamiento mínimas y que simplemente actúa como una

API Gateway actúa como un único punto de entrada para todos los clientes, así como un servicio perimetral para exponer los microservicios al mundo exterior como API administradas. Suena como un proxy inverso, pero también tiene responsabilidades adicionales como el equilibrio de carga simple, autenticación y autorización, manejo de fallas, auditoría, traducciones de protocolos y enrutamiento. El equipo de desarrollo puede seleccionar uno de los siguientes enfoques para implementar una API Gateway.

  • Constrúyalo mediante programación para tener mejores personalizaciones y control
  • Implemente un producto de puerta de enlace API existente para ahorrar tiempo de desarrollo inicial y utilizar funciones integradas avanzadas (Contras: estos productos dependen del proveedor y no son completamente gratuitos. Las configuraciones y el mantenimiento a menudo pueden ser tediosos y llevar mucho tiempo)

Algunos patrones de diseño que explican el comportamiento de API Gateway son los siguientes (Leer patrones de diseño para microservicios).

  • Agregación de puerta de enlace: agregue múltiples solicitudes de clientes (generalmente solicitudes HTTP) dirigidas a múltiples microservicios internos en una sola solicitud de cliente, reduciendo el chat y la latencia entre consumidores y servicios.
  • Descarga de puerta de enlace: habilite microservicios individuales para descargar su funcionalidad de servicio compartido al nivel de puerta de enlace API. Dichas funcionalidades transversales incluyen autenticación, autorización, descubrimiento de servicios, mecanismos de tolerancia a fallas, QoS, equilibrio de carga, registro, análisis, etc.
  • Enrutamiento de puerta de enlace (enrutamiento de capa 7, generalmente solicitudes HTTP): enruta las solicitudes a los puntos finales de microservicios internos utilizando un único punto final, para que los consumidores no necesiten administrar muchos puntos finales separados

Tenga en cuenta que una API Gateway siempre debe ser un componente de alta disponibilidad y rendimiento, ya que es el punto de entrada a todo el sistema.

Bus de eventos (Pub / sub Mediator channel para comunicación asíncrona controlada por eventos)

Consistencia eventual entre microservicios basados ​​en comunicación asíncrona controlada por eventos (Imagen: microsoft.com)

Para que diferentes partes de la aplicación se comuniquen entre sí, independientemente de la secuencia de mensajes (asíncrono) o el idioma que utilizan (lenguaje independiente), se puede utilizar el bus de eventos. La mayoría de los buses de eventos admiten mensajes de publicación / suscripción, distribuidos, punto a punto y solicitud-respuesta. Algunos buses de eventos (como en Vert.x) permiten que el lado del cliente se comunique con los nodos del servidor correspondientes utilizando el mismo bus de eventos, que es una característica genial que adoran los equipos full-stack.

Service Mesh (Sidecar para comunicación entre servicios)

Comunicación entre servicios utilizando el estilo de malla de servicio (Imagen: microservicios en la práctica)Cómo se usan las mallas de servicio en una aplicación (Imagen: christianposta.com)

Service Mesh implementa el patrón Sidecar al proporcionar infraestructura auxiliar para la comunicación entre servicios. Incluye características como resistencia (tolerancia a fallas, equilibrio de carga), descubrimiento de servicios, enrutamiento, observabilidad, seguridad, control de acceso, soporte de protocolo de comunicación, etc.

Cómo encajan las mallas de servicio en la pila de red (Imagen: christianposta.com)

En la práctica, se implementa una instancia de Sidecar junto con cada servicio (idealmente en el mismo contenedor). Pueden comunicarse a través de funciones de red primitivas del servicio. Control Plane of Service Mesh se implementa por separado para proporcionar capacidades centrales como descubrimiento de servicios, control de acceso y observabilidad (monitoreo, registro distribuido). Lo que es más importante, el estilo Service Mesh permite a los desarrolladores desacoplar las funciones de comunicación de red del código de microservicio y mantener los servicios enfocados solo en las capacidades comerciales. (Lea: Netflix Prana, Service Mesh for Microservices)

Aunque las imágenes de arriba indican conexiones directas entre servicios, la mejor manera de manejar la comunicación entre servicios sería usar un bus de eventos simple como mediador para mantener el acoplamiento en un nivel mínimo.

Backends para Frontends (BFF)

Implementación de backends para patrones de frontends y agregadores a nivel de API Gateway (Imagen: microsoft.com)

Si la aplicación necesita adaptar cada API para que se adapte al tipo de aplicación del cliente (web, móvil, diferentes plataformas), se pueden aplicar diferentes reglas (configuraciones) a través de una fachada o pueden servir compilaciones separadas basadas en las capacidades del cliente. Esto se puede implementar en el nivel de API Gateway o en paralelo al nivel de servicios. Este patrón es útil para proporcionar experiencias de usuario específicas. Sin embargo, el equipo de desarrollo debe ser lo suficientemente cuidadoso para mantener los mejores amigos hasta un límite manejable.

Mejores prácticas

Design Diseño impulsado por dominio: modele servicios en torno al dominio empresarial.

Para manejar grandes modelos y equipos, se puede aplicar el diseño controlado por dominio (DDD). Se trata de modelos grandes dividiéndolos en diferentes contextos limitados y siendo explícito sobre sus interrelaciones y dominio subyacente. Estos contextos limitados se pueden convertir en microservicios separados en el nivel de diseño de la aplicación (Leer: Contexto limitado en el diseño impulsado por dominio).

Gestión de datos descentralizada (evitar bases de datos compartidas). Cuando varios servicios consumen un esquema de datos compartido, puede crear un acoplamiento estrecho en la capa de datos. Para evitarlo, cada servicio debe tener su propia lógica de acceso a datos y un almacén de datos separado. El equipo de desarrollo es libre de elegir el método de persistencia de datos que mejor se adapte a cada servicio y naturaleza de los datos.

Evite los almacenes de datos compartidos y los mecanismos de acceso a datos (Imagen: christianposta.com)

Points Puntos finales inteligentes y canalizaciones tontas: cada servicio posee una API bien definida para la comunicación externa. Evite filtrar detalles de implementación. Para la comunicación, use siempre protocolos simples como REST sobre HTTP.

Communication Comunicación asincrónica: cuando la comunicación asincrónica se utiliza en todos los servicios, el flujo de datos no se bloquea para otros servicios.

Mensajes síncronos versus asíncronos (Imagen: microsoft.com)

Evite el acoplamiento entre servicios: los servicios deben tener un acoplamiento flexible y una alta cohesión funcional. Las causas principales del acoplamiento incluyen esquemas de bases de datos compartidas y protocolos de comunicación rígidos.

Descentralice el desarrollo: evite compartir bases de código, esquemas de datos o miembros del equipo de desarrollo entre múltiples servicios / proyectos. Deje que los desarrolladores se centren en la innovación y la calidad en la fuente.

Mantenga el conocimiento del dominio fuera de la puerta de enlace. Deje que la puerta de enlace se encargue del enrutamiento y las preocupaciones transversales (autenticación, terminación SSL).

Autenticación basada en tokens: en lugar de implementar componentes de seguridad en cada nivel de microservicios que está hablando con un repositorio de usuarios centralizado / compartido y recuperar la información de autenticación, considere implementar la autenticación a nivel de API Gateway con estándares de seguridad API ampliamente utilizados como OAuth2 y OpenID Conectar. Después de obtener un token de autenticación del proveedor de autenticación, se puede usar para comunicarse con otros microservicios.

Seguridad de microservicios con OAuth2 y OpenID Connect (Imagen: Blog de Kasun)

Nature Naturaleza impulsada por eventos: los seres humanos son agentes autónomos que pueden reaccionar a los eventos. ¿No pueden nuestros sistemas ser así? (Lea: ¿Por qué los microservicios deben ser impulsados ​​por eventos? Autonomía vs Autoridad)

Consisten Consistencia eventual: debido a la alta cohesión en los microservicios, es difícil lograr una consistencia fuerte en todo el sistema. El equipo de desarrollo tendrá que manejar la consistencia eventual a medida que se presente.

Tolerance Tolerancia a fallas: dado que el sistema se compone de múltiples servicios y componentes de middleware, las fallas pueden ocurrir en algún lugar con mucha facilidad. La implementación de patrones como interrupción de circuitos, mamparo, reintentos, tiempos de espera, fallas rápidas, almacenamiento en caché de conmutación por error, limitadores de velocidad, deslaminadores de carga en componentes tan vulnerables puede minimizar los riesgos de fallas importantes. (Lea: Diseño de una arquitectura de microservicios para fallas)

Engineering Ingeniería de productos: los microservicios funcionarán bien siempre que estén diseñados como un producto, no como un proyecto. No se trata de hacer que funcione de alguna manera y entregar antes de los plazos, sino de un compromiso a largo plazo de excelencia en ingeniería.

Microservicios en la práctica

Cuándo usar microservicios

La arquitectura de microservicios se adapta mejor a:

  • Aplicaciones con necesidades de alta escalabilidad
  • Proyectos con alta velocidad de liberación
  • Casos de negocios con dominios ricos o muchos subdominios
  • Entornos ágiles con pequeños equipos de desarrollo multifuncionales que desarrollan productos grandes en colaboración (Lea: La verdadera historia de éxito de las arquitecturas de microservicios)

Algunos marcos de referencia para implementar microservicios

  • ErtVert.x: liviano, fácil de entender / implementar / mantener, políglota (admite muchos idiomas), controlado por eventos, sin bloqueo, hasta ahora el mejor rendimiento y escalabilidad cuando se manejan necesidades de alta concurrencia con hardware mínimo, sin opina ( solo proporciona ladrillos útiles, los desarrolladores tienen la libertad de ser innovadores y crear cuidadosamente sus aplicaciones, no como los marcos restrictivos tradicionales)
  • KAkka: rendimiento satisfactorio, implementa el modelo de actor, bueno para microservicios reactivos e impulsados ​​por eventos
  • PringSpringBoot / Cloud: fácil de comenzar (paradigmas familiares), basado en el buen marco Spring anterior, un marco un poco pesado, muchas integraciones disponibles, gran apoyo de la comunidad
  • Dropwizard: bueno para el rápido desarrollo de servicios web RESTful, viene completamente cargado con algunas de las excelentes herramientas y bibliotecas de Java como Google Guava, el servidor Jetty, Logback, Hibernate Validator, Joda Time, Jersey y Jackson.

Opciones de implementación

  • Contenedores: buenos para hacer cumplir los objetivos de DevOp (desarrollo rápido, tiempo de comercialización reducido, escalamiento continuo)
  • Nube: buena para construir una infraestructura confiable y escalable para servir a usuarios dispersos geográficamente
  • Sin servidor: bueno para manejar tráficos altamente volátiles
  • Mantenga su propia infraestructura de TI: buena para aquellos que tienen altas capacidades y recursos para construir infraestructura completa

Desarrollo de conceptos en torno a microservicios.

  • Sistemas autónomos: ensamble software de sistemas independientes (como verticales en microservicios)
  • Micro frontends: divida las interfaces de usuario web monolíticas en funciones independientes que se pueden desarrollar como componentes de interfaz de usuario independientes y comunicarse directamente con microservicios

Palabras clave para google (¡y estudio!)

Diseño impulsado por dominio (DDD) | Contexto acotado (BC) | Persistencia políglota (PP) | Segregación de responsabilidad de comando y consulta (CQRS) | Separación de consulta de comando (CQS) | Abastecimiento de eventos (ES) | Teorema de la PAC | Consistencia eventual | Aplicación de doce factores | Principios SÓLIDOS |

Sugerencias de arquitectura

Arquitectura de microservicios para una aplicación de compras en línea (Imagen: microsoft.com): los desarrolladores de Microsoft proponen esta arquitectura utilizando las tecnologías de Microsoft. Aquí, API Gateway se ha diseñado para tratar a los usuarios web y móviles de manera diferente. Para la capa de datos, las tecnologías de almacenamiento de datos se seleccionan cuidadosamente de acuerdo con las capacidades empresariales (bases de datos relacionales para datos estructurados, Redis para el almacenamiento en caché temporal de datos, MongoDB y CosmosDB para datos no estructurados). Comunicación entre servicios manejada por el bus de eventos. Dejando a un lado las tecnologías, este es el patrón de integración más común utilizado en aplicaciones basadas en microservicios.Arquitectura de microservicios para una aplicación que muestra actualizaciones en tiempo real a los usuarios finales utilizando grandes cantidades de flujos de datos de entrada provenientes de varias fuentes de eventos (por ejemplo, datos de tráfico, lecturas del clima, noticias del mercado de valores, publicaciones en redes sociales, salidas de sensores). Estas secuencias de datos de entrada se recopilan inicialmente mediante un registro de eventos implementado utilizando Kafka. Persiste los datos en el disco y, por lo tanto, puede utilizarse para fines de consumo por lotes (análisis, informes, ciencia de datos, copias de seguridad, auditoría) o enviarse para fines de consumo en tiempo real (análisis operativo, CEP, paneles de administración, aplicaciones de alerta). Sin embargo, de acuerdo con este diagrama, la corriente entrante continua se divide en micro lotes con intervalos específicos utilizando Spark y se alimenta al motor WSO2 Siddhi CEP. Luego identifica los eventos y los persiste en formas no estructuradas utilizando los almacenes de datos MongoDB. Los microservicios consumen estos datos y los muestran a los usuarios finales. Si observa detenidamente el diseño, dado que el bus de eventos Vert.x tiene la capacidad de crear conexiones con componentes de interfaz de usuario frontend, esa característica se ha utilizado para actualizar de manera eficiente solo las partes relevantes en la interfaz de usuario. Dejando de lado las tecnologías, esta es una gran arquitectura para aplicaciones basadas en microservicios sin bloqueo controladas por eventos.Arquitectura nativa de microservicios omnicanal en la nube para una aplicación de gestión de pedidos (Imagen: ibm.com): una especialidad principal en este diseño es que, en lugar de utilizar una API Gateway, los arquitectos de IBM han propuesto una capa de borde con backends separados para cada canal del cliente ( aplicaciones móviles, aplicaciones web, dispositivos IOT, consumidores API). Otra especialidad es que la capa de microservicios se divide en 2 subcapas llamadas capa de lógica de negocios y capa fundamental. La Capa Fundacional (también conocida como Capa de Servicios Básicos) se ocupa de las tareas de persistencia e integración utilizando varios servicios nativos de la nube (almacenes de datos en la nube, motores Elasticsearch que integran e indexan una conversación de Watson). La capa de lógica de negocios integra datos de la capa fundamental y ofrece capacidades comerciales significativas. Esta sería una gran arquitectura para servir a una gran cantidad de usuarios que están dispersos geográficamente y tienen acceso a la aplicación a través de varias plataformas.
¿Lo estás disfrutando hasta ahora? No olvides recomendar