Close

Cómo crear microservicios

Prácticas recomendadas para la transición a una arquitectura de microservicios

Primer plano de Chandler Harris
Sten Pittet

gestor de Productos sénior


Imagina que tu aplicación se basa en un código y es bastante grande y monolítica. Parecía que iba bien, hasta que empezó a dar problemas. Te gustaría que pudiera evolucionar y ser más resiliente, escalable e implementable de forma independiente. Para conseguirlo, debes rediseñar la estructura de la aplicación a nivel de microservicios.

Los microservicios cada vez son más populares, al tiempo que las aplicaciones ganan en distribución y complejidad. El principio rector de los microservicios es crear una aplicación dividiendo sus componentes empresariales en pequeños servicios que se puedan implementar y que funcionen de forma independiente los unos de los otros. La separación de intereses entre servicios se define como “límites de servicios”.

Los límites de servicios están estrechamente vinculados a las demandas empresariales y a los límites jerárquicos organizativos. Los servicios individuales pueden estar vinculados a los distintos equipos, presupuestos y hojas de ruta. Algunos ejemplos de límites de servicios pueden ser los servicios de procesamiento de pagos y autenticación de usuarios. Los microservicios difieren de las prácticas heredadas de desarrollo de software, en las que se agrupaban todos los componentes.

Este documento hace referencia a una startup de pizzería imaginaria llamada “Pizzup” como representación de la aplicación de microservicios en una empresa moderna de software.

Cómo crear microservicios


Paso 1: comienza con un monolito

La primera práctica recomendada de microservicios es que probablemente no los necesites. Si no tienes ningún usuario para tu aplicación, es probable que los requisitos empresariales cambien rápidamente mientras estás desarrollando tu producto viable mínimo. Esto se debe sencillamente a la naturaleza del desarrollo de software y al ciclo de feedback que se debe producir durante la identificación de las capacidades empresariales clave que tu sistema debe proporcionar. Los microservicios añaden sobrecarga exponencial y complejidad de gestión. Por este motivo, en nuevos proyectos supone mucha menos carga de trabajo mantener todo el código y la lógica dentro de una sola base de código, ya que facilita el mover los límites de los diferentes módulos de tu aplicación.

Por ejemplo, en el caso de Pizzup empezamos con un problema sencillo por resolver: queremos que los clientes puedan pedir pizza por Internet.

Usuario de Pizzup diciendo: ¡Como usuario, puedo pedir pizza por Internet!
Icono de almacén de código
Material relacionado

Comparación entre la arquitectura monolítica y la arquitectura de microservicios

Icono de tres anillos
Ver la solución

Gestiona tus componentes con Compass

Cuando empecemos a pensar en los pedidos de pizza, determinaremos las distintas capacidades necesarias en nuestra aplicación a fin de satisfacer esa necesidad. Deberemos gestionar una lista de las diferentes pizzas que podamos hacer, así como dejar a los clientes elegir una o varias pizzas, gestionar el pago, programar la entrega, etc. Podemos decidir que la posibilidad de que los clientes creen una cuenta les facilita la tarea de volver a hacer un pedido la próxima vez que usen Pizzup; además, después de hablar con los primeros usuarios, podríamos descubrir que el seguimiento en directo de la entrega y la compatibilidad móvil nos darían ventaja sobre la competencia.

Gráfico donde se muestra la diferencia entre los usos de usuario final y de administrador para la aplicación Pizzup.

Lo que al principio era una necesidad sencilla se convierte rápidamente en una lista de nuevas funciones.

Los microservicios funcionan cuando conoces bien los diferentes servicios que tu sistema necesita. Sin embargo, son mucho más difíciles de manejar si los requisitos básicos de una aplicación no están bien definidos. Resulta bastante costoso redefinir las interacciones de servicios, API y estructuras de datos en los microservicios ya que puedes tener muchos más elementos que se deben coordinar. Te aconsejamos simplificar las cosas hasta que hayas recopilado suficientes comentarios de los usuarios para tener la seguridad de que se han comprendido las necesidades básicas de tus clientes y que se ha llevado la planificación de acuerdo con ellas.

Una pequeña advertencia: la creación de un monolito puede dificultar rápidamente el desglose de un código en fragmentos más pequeños. Lo ideal es tener identificados módulos claros para poder extraerlos más tarde del monolito. Asimismo, puedes empezar separando la lógica de tu interfaz de usuario web y asegurarte de que interactúa con tu backend mediante una API de RESTful a través de HTTP. Esto facilitará la transición a microservicios cuando muevas algunos de los recursos de la API a distintos servicios.

Paso 2: organiza tu equipo de forma correcta

Hasta ahora, podía parecer que la compilación de microservicios era, sobre todo, una cuestión técnica. Hay que dividir una base de código en varios servicios, implementar los patrones correctos para fallar de forma limpia y recuperarte de las incidencias en la red, lidiar con la coherencia de los datos, supervisar la carga de servicio, etc. Habrá muchos conceptos nuevos que comprender, pero una cosa que no se debe ignorar es que deberás reestructurar la forma en que se organizan tus equipos.

La ley de Conway existe y se puede observar en cualquier tipo de equipo. Si un equipo de software está organizado con un equipo de backend, uno de frontend y otro de operaciones que trabajan de manera independiente, terminarán entregando monolitos de frontend y backend separados que se presentarán al equipo de operaciones para que los entreguen en la producción. Este tipo de estructura no es una buena opción para los microservicios, ya que cada servicio se tratará como su propio producto que debe enviarse independientemente de los demás.

En su lugar, debes crear equipos de DevOps que tengan todas las competencias necesarias para desarrollar y mantener los servicios de los que están a cargo. Organizar tus equipos de esta manera presenta grandes ventajas. En primer lugar, todos tus desarrolladores comprenderán mejor el impacto de tu código en la producción; esto ayudará a producir una mejor publicación y a reducir el riesgo de ver incidencias publicadas que llegan a los clientes. En segundo lugar, las implementaciones resultarán más naturales para cada equipo, ya que trabajarán juntos en las mejoras en el código, así como en la automatización de la canalización de implementaciones.

Paso 3: divide el monolito para compilar una arquitectura de microservicios

Cuando hayas determinado los límites de tus servicios y hayas descubierto cómo puedes reestructurar tus equipos, puedes empezar a dividir el monolito para crear microservicios. Estos son los puntos clave que tener en cuenta en ese momento.

Simplifica la comunicación entre servicios con una API basada en REST

Si aún no estás usando una API basada en REST, ahora sería un buen momento para adoptarla. Como explica Martin Fowler, te interesará tener “endpoints inteligentes y canales simples”. Esto quiere decir que el protocolo de comunicación entre tus servicios debe ser lo más sencillo posible y que solo se encargue de transmitir los datos sin transformarlos. La magia se produce en los mismos endpoints: reciben una solicitud, la procesan y emiten una respuesta.

Las arquitecturas de microservicios se esfuerzan por mantener las cosas lo más sencillas posible para evitar dependencias estrechas entre componentes. En algunos casos, es posible que acabes utilizando una arquitectura orientada a eventos con comunicaciones asincrónicas basadas en mensajes. Pero, una vez más, debes echar un vistazo a los servicios básicos de cola de mensajes como RabbitMQ y evitar añadir complejidad a los mensajes transmitidos a través de la red.

Divide los datos en contextos delimitados o dominios de datos

Las aplicaciones monolíticas utilizan una sola base de datos para todas las funciones empresariales de la aplicación. Cuando un monolito se divide en microservicios, es posible que esta base de datos única ya no sea práctica. De hecho, una base de datos centralizada puede convertirse en un cuello de botella para el escalado del tráfico. Si un servicio en particular accede a la base de datos con una carga elevada, puede interrumpir el acceso a la base de datos por parte de otros servicios. Además, una base de datos única puede convertirse en un cuello de botella de colaboración para varios equipos que intentan modificar el esquema al mismo tiempo. Esto puede requerir que la base de datos se divida o que se agreguen herramientas de almacenamiento de datos adicionales para respaldar las necesidades de los datos de los microservicios.

La refactorización de un esquema de base de datos monolítico puede ser una operación delicada. Es importante determinar con claridad qué conjuntos de datos necesita cada servicio y las superposiciones. Esta planificación de esquemas se puede realizar mediante contextos delimitados, que son un patrón de diseño por dominio. Un contexto delimitado define un sistema autónomo, que incluye lo que puede entrar al sistema o salir de él.

En este sistema, cuando un usuario accede a un pedido, puedes ver la información del cliente en la tabla, y la misma tabla puede servir también para rellenar la factura gestionada por el sistema de facturación. Esto parece lógico y sencillo pero, con los microservicios, querrás que los servicios se desacoplen para que sea posible acceder a las facturas, aunque el sistema de pedidos se haya caído. Además, esto permite optimizar o perfeccionar la tabla de facturas independientemente de las demás. De esta forma, cada servicio puede terminar teniendo su propio almacén de datos para mantener los datos que necesita.

También presenta nuevos problemas, ya que acabarás con algunos datos duplicados en diferentes bases de datos. Los contextos delimitados pueden determinar la mejor estrategia para gestionar datos duplicados o compartidos. Puedes adoptar una arquitectura orientada a eventos para ayudar a sincronizar datos en varios servicios. Por ejemplo, es posible que tus servicios de facturación y seguimiento de entregas estén escuchando eventos emitidos por los servicios de cuentas cuando un cliente actualiza su información personal. Tras recibir el evento, estos servicios actualizarán su almacén de datos de forma pertinente. Esta arquitectura orientada a eventos facilita la lógica del servicio de la cuenta, ya que no tiene que conocer los demás servicios dependientes. Simplemente le dice al sistema lo que ha hecho y otros servicios escuchan y actúan en consecuencia.

También puedes conservar toda la información del cliente en el servicio de la cuenta y mantener únicamente una referencia de clave externa en tu servicio de facturación y entrega. Luego, los servicios interactúan con el servicio de la cuenta para obtener los datos pertinentes del cliente cuando fuera necesario, en lugar de duplicar los registros existentes. No hay soluciones universales para estos problemas y tendrás que analizar cada caso concreto para determinar cuál es el mejor enfoque.

Compila tu arquitectura de microservicios en caso de fallos

Ya hemos visto las grandes ventajas que pueden ofrecerte los microservicios sobre una arquitectura monolítica. Son de tamaño más pequeño y están especializados, de modo que son fáciles de entender. Están desacoplados, lo que significa que puedes refactorizar un servicio sin temer estropear los demás componentes del sistema, o bien ralentizar el desarrollo de los otros equipos. Asimismo, ofrecen más flexibilidad a tus desarrolladores, ya que pueden elegir diferentes tecnologías si es necesario sin verse limitados por las necesidades de los otros servicios.

En resumen, contar con una arquitectura de microservicios facilita el desarrollo y el mantenimiento de cada capacidad empresarial. Pero las cosas se vuelven más complicadas cuando nos fijamos en todos los servicios en conjunto y en cómo deben interactuar para realizar acciones. Tu sistema ahora está distribuido y cuenta con varios puntos de error, por lo que debes hacerte cargo de todo eso. Debes tener en cuenta no solo los casos en los que un servicio no responde, sino también la capacidad de lidiar con respuestas de red más lentas. A veces, recuperarse de un error también puede resultar complicado, ya que debes asegurarte de que los servicios que vuelvan a estar disponibles no se inunden de mensajes pendientes.

Cuando empieces a extraer capacidades de tus sistemas monolíticos, asegúrate de que tus diseños están preparados para evitar los errores desde el principio.

Haz hincapié en la supervisión para facilitar las pruebas de microservicios

Las pruebas son otro inconveniente de los microservicios en comparación con un sistema monolítico. Una aplicación compilada como una sola base de código no necesita mucho para tener un entorno de pruebas en marcha. En la mayoría de los casos, tendrás que iniciar un servidor de backend acoplado con una base de datos para poder ejecutar tu conjunto de pruebas.

En el mundo de los microservicios, las cosas no son tan fáciles. Cuando se trata de pruebas unitarias, seguirá siendo bastante similar al enfoque monolítico y no deberías tener más dificultades a ese nivel. Sin embargo, en lo que respecta a la integración y las pruebas del sistema, las cosas se ponen mucho más difíciles. Es posible que tengas que iniciar varios servicios a la vez y poner en marcha diferentes almacenes de datos, y que tu configuración deba incluir colas de mensajes que no necesitabas con el monolito. En este caso, resulta mucho más costoso realizar pruebas funcionales y el cada vez mayor número de elementos móviles complica mucho la predicción de los diferentes tipos de errores que se pueden producir.

La supervisión permite identificar pronto las incidencias y reaccionar en consecuencia. Tienes que entender los puntos de referencia de tus diferentes servicios y saber reaccionar no solo cuando dejen de estar operativos, sino también cuando se comporten de manera inesperada. Una ventaja de adoptar una arquitectura de microservicios es que tu sistema debe ser resistente a errores parciales, por lo que, si empiezas a ver anomalías en el servicio de seguimiento de entregas de nuestra aplicación Pizzup, no será tan malo como si se tratara de un sistema monolítico. Nuestra aplicación debe diseñarse para que todos los demás servicios respondan correctamente y dejar que nuestros clientes pidan pizza mientras restauramos el seguimiento en vivo.

Adopta la entrega continua para reducir la fricción de las implementaciones

La publicación manual de un sistema monolítico en la producción es una tarea tediosa y arriesgada, pero no imposible. Por supuesto, no recomendamos este enfoque y animamos a todos los equipos de software a adoptar la entrega continua para todo tipo de desarrollo; sin embargo, al comienzo de un proyecto, podrías encargarte tú mismo de las primeras implementaciones a través de la línea de comandos.

Este enfoque no resulta sostenible cuando se tiene un número cada vez mayor de servicios que se deben implementar varias veces al día. Por lo tanto, como parte de la transición a los microservicios, es muy importante que adoptes la entrega continua para reducir el riesgo de fallos de publicación, así como asegurarte de que tu equipo se centra en la compilación y ejecución de la aplicación, en lugar de quedarse atascado en la implementación. Poner en práctica la entrega continua también significará que tu servicio ha aprobado las pruebas de aceptación antes de la producción. Por supuesto, se producirán errores, pero, con el tiempo, crearás un sólido conjunto de pruebas que aumentará la seguridad de tu equipo con respecto a la calidad de las publicaciones.

La ejecución de microservicios no es un sprint


Los microservicios son una práctica recomendada muy adoptada en el sector. En el caso de proyectos complejos, ofrecen una mayor flexibilidad en la forma de desarrollar e implementar software. Asimismo, ayudan a identificar y formalizar los componentes empresariales de tu sistema, lo que resulta útil cuando se tienen varios equipos trabajando en la misma aplicación. Pero también existen inconvenientes claros en la gestión de sistemas distribuidos, y la división de una arquitectura monolítica solo se debe realizar cuando se comprenden claramente los límites de servicios.

La compilación de microservicios debe considerarse un viaje, no el objetivo inmediato de un equipo. Empieza poco a poco para conocer los requisitos técnicos de un sistema distribuido, cómo fallar de forma limpia y cómo escalar componentes individuales. Luego, puedes extraer gradualmente más servicios a medida que vas adquiriendo experiencia y conocimientos.

La migración a una arquitectura de microservicios no tiene que llevarse a cabo mediante un único esfuerzo integral. Una apuesta más segura es la estrategia iterativa de migrar secuencialmente componentes más pequeños a los microservicios. Identifica los límites de servicios mejor definidos dentro de una aplicación monolítica establecida y trabaja iterativamente para desacoplarlos en su propio microservicio.

En conclusión...


En resumen, los microservicios constituyen una estrategia beneficiosa tanto para el proceso de desarrollo de código técnico sin procesar como para la estrategia general de la organización empresarial. Además, ayudan a organizar los equipos en unidades centradas en desarrollar y poseer funciones empresariales específicas. Este enfoque granular mejora la comunicación y la eficiencia empresariales a nivel general. Pero hay un precio a pagar por obtener los beneficios de los microservicios. Es importante que los límites de servicios estén claramente definidos antes de migrar a una arquitectura de microservicios.

Aunque una arquitectura de microservicios tiene un gran número de ventajas, también aumenta la complejidad. Atlassian ha desarrollado Compass para ayudar a las empresas a gestionar las complejidades de las arquitecturas distribuidas a medida que escalan. Es una plataforma de experiencia extensible para desarrolladores que reúne en un lugar centralizado que admite búsquedas información desconectada sobre todos los procesos de ingeniería y la colaboración en equipo.

Sten Pittet
Sten Pittet

Llevo 10 años en el negocio del software desempeñando diversas funciones, desde el desarrollo hasta la gestión de productos. Tras pasar los últimos 5 años en Atlassian trabajando en herramientas para desarrolladores, ahora escribo sobre compilación de software. Fuera del trabajo, me dedico a perfeccionar mis habilidades como padre con el maravilloso hijo que tengo.


Compartir este artículo

Lecturas recomendadas

Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.

Ilustración de Devops

Comunidad de Compass

ilustración de superar obstáculos

Tutorial: Crear un componente

Ilustración de un mapa

Comienza a usar Compass de forma gratuita

Suscríbete para recibir el boletín de DevOps

Thank you for signing up