Esta guía de referencia es la primera de una serie de cuatro partes sobre el diseño, la compilación y la implementación de microservicios. En esta serie, se describen los diversos elementos de una arquitectura de microservicios. En ella, se incluye información sobre los beneficios y las desventajas del patrón de arquitectura de microservicios, y cómo aplicarlo.
- Introducción a los microservicios (este documento)
- Refactoriza de aplicaciones monolíticas en microservicios
- Comunicación entre servicios en una configuración de microservicios
- Seguimiento distribuido en una aplicación de microservicios
Esta serie está dirigida a desarrolladores y arquitectos de aplicaciones que diseñan y, luego, implementan la migración para refactorizar una aplicación monolítica en una aplicación de microservicios.
Aplicaciones monolíticas
Una aplicación monolítica es una aplicación de software de un solo nivel en la que se combinan diferentes módulos en un solo programa. Por ejemplo, si compilas una aplicación de comercio electrónico, se espera que la aplicación tenga una arquitectura modular alineada con los principios de programación orientada a objetos (OOP). En el siguiente diagrama, se muestra un ejemplo de configuración de la aplicación de comercio electrónico, en el que la aplicación consta de varios módulos. En una aplicación monolítica, los módulos se definen mediante una combinación de construcciones del lenguaje de programación (como los paquetes de Java) y artefactos de compilación (como los archivos JAR de Java).
Figura 1. Diagrama de una aplicación de comercio electrónico monolítica con varios módulos que usan una combinación de construcciones de lenguaje de programación.
En la figura 1, los diferentes módulos de la aplicación de comercio electrónico corresponden a la lógica empresarial para el pago, la entrega y la administración de pedidos. Todos estos módulos se empaquetan y se implementan como un solo ejecutable lógico. El formato real depende del lenguaje y del framework de la aplicación. Por ejemplo, muchas aplicaciones Java se empaquetan como archivos JAR y se implementan en servidores de aplicaciones, como Tomcat o Jetty. De manera similar, una aplicación Rails o Node.js se empaqueta como una jerarquía de directorios.
Beneficios de la aplicación monolítica
La arquitectura monolítica es una solución convencional para compilar aplicaciones. Las siguientes son algunas ventajas de adoptar un diseño monolítico para tu aplicación:
- Puedes implementar pruebas de extremo a extremo de una aplicación monolítica mediante herramientas como Selenium.
- Para implementar una aplicación monolítica, simplemente puedes copiar la aplicación empaquetada en un servidor.
- Todos los módulos de una aplicación monolítica comparten memoria, espacio y recursos, de modo que puedes usar una sola solución para abordar problemas cruzados, como el registro, el almacenamiento en caché y la seguridad.
- El enfoque monolítico puede proporcionar ventajas de rendimiento, ya que los módulos pueden llamarse entre sí directamente. Por el contrario, los microservicios suelen requerir una llamada de red para comunicarse entre sí.
Desafíos de la aplicación monolítica
Las aplicaciones monolíticas complejas suelen ser cada vez más difíciles de compilar, depurar y razonar. En algún momento, los problemas superan los beneficios.
- Las aplicaciones suelen crecer con el tiempo. Puede resultar complicado implementar cambios en una aplicación grande y compleja que tenga módulos estrechamente vinculados. Debido a que cualquier cambio de código afecta a todo el sistema, debes coordinar de manera exhaustiva los cambios. La coordinación de cambios hace que el proceso general de desarrollo y pruebas sea mucho más largo en comparación con las aplicaciones de microservicios.
- Puede ser complicado lograr la integración y la implementación continuas (CI/CD) con una aplicación monolítica grande. Esta complejidad se debe a que debes volver a implementar la aplicación completa para poder actualizar cualquier parte de ella. Además, es probable que tengas que realizar pruebas manuales extensas en toda la aplicación para verificar si hay regresiones.
- Las aplicaciones monolíticas pueden ser difíciles de escalar cuando diferentes módulos tienen requisitos de recursos en conflicto. Por ejemplo, un módulo puede implementar una lógica de procesamiento de imágenes que consume muchos recursos de CPU. Otro módulo puede ser una base de datos en la memoria. Debido a que estos módulos se implementan juntos, debes hacer sacrificios en la elección del hardware.
- Debido a que todos los módulos se ejecutan dentro del mismo proceso, un error en cualquier módulo, como una fuga de memoria, puede provocar la caída de todo el sistema.
- Las aplicaciones monolíticas agregan complejidad cuando deseas adoptar nuevos frameworks y lenguajes. Por ejemplo, reescribir una aplicación completa para usar un framework nuevo es costoso (en tiempo y dinero) incluso si ese framework es bastante mejor.
Aplicaciones basadas en microservicios
Por lo general, un microservicio implementa un conjunto de funciones o características distintas. Cada microservicio es una miniaplicación que tiene su propia arquitectura y lógica empresarial. Por ejemplo, algunos microservicios exponen una API que consumen otros microservicios o los clientes de la aplicación, como integraciones de terceros con puertas de enlace de pago y logística.
En la figura 1, se muestra una aplicación de comercio electrónico monolítica con varios módulos. En el siguiente diagrama, se muestra una posible descomposición de la aplicación de comercio electrónico en microservicios:
Figura 2. Diagrama de una aplicación de comercio electrónico con áreas funcionales implementadas por microservicios.
En la figura 2, una microentrega dedicada implementa cada área funcional de la aplicación de comercio electrónico. Cada servicio de backend puede exponer una API, y los servicios consumen las API que proporcionan otros servicios. Por ejemplo, para procesar páginas web, los servicios de IU invocan el servicio de confirmación de la compra y otros servicios. Los servicios también pueden usar comunicación asíncrona basada en mensajes. Para obtener más información sobre cómo los servicios se comunican entre sí, consulta el tercer documento de esta serie, Comunicación entre servicios en una configuración de microservicios.
El patrón de arquitectura de microservicios cambia significativamente la relación entre la aplicación y la base de datos. En lugar de compartir una sola base de datos con otros servicios, recomendamos que cada servicio tenga su propia base de datos que se adapte mejor a sus requisitos. Cuando tienes una base de datos para cada servicio, te aseguras que el acoplamiento bajo entre los servicios porque todas las solicitudes de datos pasan a través de la API del servicio y no a través de la base de datos compartida directamente. En el siguiente diagrama, se muestra un patrón de arquitectura de microservicios en el que cada servicio tiene su propia base de datos:
Figura 3. Cada servicio en una arquitectura de microservicios tiene su propia base de datos.
En la figura 3, el servicio de pedidos en la aplicación de comercio electrónico funciona bien con una base de datos orientada a documentos que tiene capacidades de búsqueda en tiempo real. Los servicios de pago y entrega se basan en las garantías sólidas de atomicidad, coherencia, aislamiento y durabilidad (ACID) de una base de datos relacional.
Beneficios de los microservicios
El patrón de arquitectura de microservicios aborda el problema de la complejidad descrito en la sección anterior Desafíos de la aplicación monolítica. Una arquitectura de microservicios proporciona los siguientes beneficios:
- Aunque la funcionalidad total no se modifica, debes usar microservicios para separar la aplicación en fragmentos o servicios administrables. Cada servicio tiene un límite bien definido en forma de RPC o API controlada por mensajes. Por lo tanto, los servicios individuales pueden ser más rápidos de desarrollar y más fáciles de comprender y mantener.
- Los equipos autónomos pueden desarrollar servicios individuales de forma independiente. Puedes organizar los microservicios en torno a los límites comerciales, no las capacidades técnicas de un producto. Debes organizar tus equipos para una sola responsabilidad independiente de todo el ciclo de vida del software asignado, desde el desarrollo y las pruebas hasta la implementación, el mantenimiento y la supervisión.
- El proceso de desarrollo de microservicios independiente también permite que los desarrolladores escriban cada microservicio en un lenguaje de programación diferente, lo que crea una aplicación políglota. Cuando usas el lenguaje más eficaz para cada microservicio, puedes desarrollar una aplicación con mayor rapidez y optimizarla a fin de reducir la complejidad del código y aumentar el rendimiento y la funcionalidad.
- Cuando separas las capacidades de una aplicación monolítica, puedes hacer que los equipos independientes lancen su microservicio de forma independiente. Los ciclos de lanzamiento independientes pueden ayudar a mejorar la velocidad y el tiempo de salida del producto de tus equipos.
- La arquitectura de microservicios también te permite escalar cada servicio de forma independiente. Puedes implementar la cantidad de instancias de cada servicio que satisfagan sus restricciones de capacidad y disponibilidad. También puedes usar el hardware que mejor se adapte a los requisitos de recursos de un servicio. Cuando escalas servicios de forma independiente, ayudas a aumentar la disponibilidad y la confiabilidad de todo el sistema.
A continuación, se muestran algunas instancias específicas en las que puede resultar beneficioso migrar una aplicación monolítica a una de microservicio:
- Implementar mejoras en la escalabilidad, la administración, la agilidad o la velocidad de la entrega.
- Reescribe de forma gradual una aplicación heredada grande en un lenguaje moderno y una technology stack para satisfacer las nuevas demandas de la empresa.
- Extraer aplicaciones empresariales o transversales entre servicios para que puedas reutilizarlas en varios canales. Algunos ejemplos de servicios que puedes volver a usar incluyen servicios de pago, servicios de acceso, servicios de encriptación, servicios de búsqueda de vuelos, servicios de perfil de clientes y servicios de notificación.
- Adopta un lenguaje o framework para propósitos específicos de una funcionalidad específica de una aplicación monolítica existente.
Desafíos de los microservicios
Los microservicios tienen algunos desafíos en comparación con las aplicaciones monolíticas, incluidos los siguientes:
- Un desafío importante de los microservicios es la complejidad que se produce debido a que la aplicación es un sistema distribuido. Los desarrolladores deben elegir e implementar un mecanismo de comunicación entre servicios. Los servicios también deben manejar fallas parciales y la falta de disponibilidad de servicios ascendentes.
Otro desafío con los microservicios es que necesitas administrar transacciones en diferentes microservicios (lo que también se conoce como transacción distribuida). Las operaciones comerciales que actualizan varias entidades comerciales son bastante comunes y, por lo general, se aplican de una manera atómica en la que todas las operaciones se aplican o todo falla. Cuando unes varias operaciones en una sola transacción de base de datos, garantizas la atomicidad.
En una aplicación basada en microservicios, las operaciones empresariales pueden estar distribuidas en diferentes microservicios, por lo que debes actualizar varias bases de datos que pertenezcan a servicios diferentes. Si ocurre un error, no es trivial realizar un seguimiento de la falla o del éxito de las llamadas a los diferentes microservicios y revertir el estado. En el peor de los casos, se pueden generar datos incoherentes entre los servicios cuando la reversión del estado debido a fallas no ocurrió de forma correcta. Si deseas obtener información sobre las diversas metodologías para configurar transacciones distribuidas entre servicios, consulta el tercer documento de esta serie, Comunicación entre servicios en una configuración de microservicios.
Las pruebas integrales de aplicaciones basadas en microservicios son más complejas que la prueba de una aplicación monolítica. Por ejemplo, para probar la funcionalidad de procesar un pedido en un servicio de comercio electrónico monolítico, selecciona elementos, agrégalos a un carrito y, luego, paga. A fin de probar el mismo flujo en una arquitectura basada en microservicios, varios servicios, como frontend, pedido y pago, se llaman entre sí para completar la ejecución de la prueba
Implementar una aplicación basada en microservicios es más complejo que implementar una aplicación monolítica. Por lo general, una aplicación de microservicio consta de muchos servicios, cada uno de los cuales tiene varias instancias de entorno de ejecución. También debes implementar un mecanismo de descubrimiento de servicios que permita que un servicio descubra las ubicaciones de los demás servicios con los que necesite comunicarse.
Una arquitectura de microservicios agrega sobrecarga de operaciones porque hay más servicios que supervisar y sobre los cuales generar alertas. La arquitectura de microservicios también tiene más puntos de falla debido al aumento de los puntos de comunicación de servicio a servicio. Una aplicación monolítica se puede implementar en un clúster de servidor de aplicaciones pequeño. Una aplicación basada en microservicios puede tener decenas de servicios independientes para compilar, probar, implementar y ejecutar, posiblemente en varios lenguajes y entornos. Todos estos servicios deben agruparse en clústeres para la conmutación por error y la resiliencia. La producción de una aplicación de microservicios requiere una infraestructura de supervisión y operaciones de alta calidad.
La división de los servicios en una arquitectura de microservicios permite que la aplicación realice más funciones al mismo tiempo. Sin embargo, debido a que los módulos se ejecutan como servicios aislados, se agrega latencia al tiempo de respuesta debido a las llamadas de red entre servicios.
No todas las aplicaciones son lo suficientemente grandes para desglosarse en microservicios. Además, algunas aplicaciones requieren una integración estrecha entre los componentes, por ejemplo, las aplicaciones que deben procesar transmisiones rápidas de datos en tiempo real. Cualquier capa adicional de comunicación entre los servicios puede ralentizar el procesamiento en tiempo real. Pensar en la comunicación entre servicios con anticipación puede proporcionar estadísticas útiles para marcar con claridad los límites del servicio.
Cuando decidas si la arquitectura de los microservicios es la mejor opción para tu aplicación, ten en cuenta los siguientes puntos:
- Las prácticas recomendadas de microservicios requieren bases de datos por servicio. Cuando modeles datos para tu aplicación, observa si las bases de datos por servicio se ajustan a tu aplicación.
- Cuando implementas una arquitectura de microservicios, debes instrumentar y supervisar el entorno para poder identificar cuellos de botella, detectar y prevenir fallas, y fundamentar los diagnósticos.
- En una arquitectura de microservicios, cada servicio tiene controles de acceso independientes. Para ayudar a garantizar la seguridad, debes proteger el acceso a cada servicio dentro del entorno y de las aplicaciones externas que consumen sus API.
- La comunicación síncrona entre servicios generalmente reduce la disponibilidad de una aplicación. Por ejemplo, si el servicio de pedidos en una aplicación de comercio electrónico invoca de forma síncrona otros servicios ascendentes y, si esos servicios no están disponibles, no puede crear un pedido. Por lo tanto, te recomendamos que implementes una comunicación asíncrona basada en mensajes.
Cuándo migrar una aplicación monolítica a microservicios
Si ya ejecutas con éxito una aplicación monolítica, la adopción de microservicios es un costo de inversión significativo para tu equipo. Distintos equipos implementan los principios de los microservicios de diferentes maneras. Cada equipo de ingeniería tiene resultados únicos para lo pequeños que son sus microservicios o la cantidad de microservicios que necesitan.
A fin de determinar si los microservicios son el mejor enfoque para la aplicación, primero identifica los objetivos o problemas empresariales clave que deseas abordar. Puede haber formas más sencillas de alcanzar los objetivos o solucionar los problemas que identifiques. Por ejemplo, si quieres escalar la aplicación más rápido, es posible que el ajuste de escala automático sea una solución más eficiente. Si encuentras errores en la producción, puedes comenzar por implementar pruebas de unidades e integración continua (CI).
Si crees que un enfoque de microservicio es la mejor manera de lograr tus objetivos, primero extrae un servicio de la aplicación monolítica y desarrolla, prueba e implementa en producción. Para obtener más información, consulta el siguiente documento de esta serie, Refactoriza de aplicaciones monolíticas en microservicios. Después de extraer de forma correcta un servicio y ejecutarlo en producción, comienza a extraer el siguiente servicio y continúa aprendiendo de cada ciclo.
El patrón de arquitectura de microservicios divide un sistema en un conjunto de servicios que se pueden implementar de forma independiente. Cuando desarrollas una aplicación monolítica, debes coordinar equipos grandes, lo que puede causar un desarrollo de software lento. Cuando implementas una arquitectura de microservicios, permites que equipos pequeños y autónomos trabajen en paralelo, lo que puede acelerar el desarrollo.
En el siguiente documento de esta serie, Refactoriza de aplicaciones monolíticas en microservicios, puedes aprender varias estrategias a fin de refactorizar una aplicación monolítica en microservicios.
¿Qué sigue?
- Lee el siguiente documento de esta serie a fin de obtener información sobre las estrategias de refactorización de aplicaciones para descomponer microservicios.
- Lee el tercer documento de esta serie para obtener información sobre la comunicación entre servicios en una configuración de microservicios.
- Lee el cuarto documento final de esta serie para obtener información sobre el seguimiento distribuido de solicitudes entre microservicios.