Hola, soy Stanislav Yablonskiy, desarrollador principal de servidores en Pixonic (MY.GAMES). Los microservicios son un enfoque para el desarrollo de software (principalmente desarrollo backend) donde la funcionalidad se descompone en los componentes más pequeños posibles, cada uno de los cuales funciona de forma independiente. Cada componente tiene su propia API. Puede tener su propia base de datos y puede ser escrito en su propio lenguaje de programación. Los microservicios son muy populares hoy en día, pero su uso introduce una considerable superioridad en términos de red, memoria y CPU. Cada llamada se convierte en la necesidad de serializar, enviar y recibir datos a través de la red. Además, ya no es posible utilizar transacciones de base de datos clásicas, lo que lleva a transacciones distribuidas o eventual consistencia. Las transacciones distribuidas son lentas y costosas, mientras que la eventual coherencia significa que los resultados de las operaciones pueden no aparecer de inmediato, y los datos pueden ser temporalmente inconsistentes. El uso de microservicios obliga a los desarrolladores a escribir más código en cada servicio individual debido a las dificultades de acceder a la lógica ya escrita de otros servicios. A veces, es difícil reutilizar el código existente, o puede que ni siquiera sepa que existe, ya que otras personas pueden estar trabajando en un proyecto diferente. Los microservicios se superponen Debug sobre la cabeza Debugging se vuelve mucho más difícil con microservicios. Un debugger regular es casi inútil en tales condiciones ya que no se puede debugar todos los servicios de una vez. Sin un sistema de registro, rastreo y métricas correctamente configurado, el debugging es casi imposible hasta que el problema se localiza. Esto significa que necesita un entorno especial en el que no solo se ejecute el servicio que se está debugando, sino también todas sus dependencias (otros servicios, bases de datos, filas, etc.). HTTP sobrecargado El protocolo HTTP tiene una gran cantidad de funcionalidades integradas. soporta varias rutas, métodos de paso de parámetros, códigos de respuesta, y es soportado por muchos servicios listos para el uso (incluidos los proxies). pero no es ligero - obliga a cada servicio a implementar un montón de código no tan eficiente para analizar y generar caminos, encabezados, y así sucesivamente. Proyecto Overhead Se requiere serialización para la comunicación de red y deserialización al recibir mensajes. Cuando utilices protobuf para el intercambio de mensajes, necesitas: Creación de objetos, convertirlos en arreglos de cambio, Desechar inmediatamente después del uso. Esto crea mucho trabajo adicional para el colector de basura o el gerente de memoria dinámica. Redes de arriba La transmisión de datos a través de la red aumenta el tiempo de respuesta del servicio y aumenta el consumo de memoria y CPU, incluso si los microservicios se ejecutan en el mismo host. Memoria Overhead Enviar y recibir mensajes requiere el mantenimiento de estructuras de datos adicionales, utilizando filamentos separados y sincronizándolos.Cada proceso separado, especialmente uno que se ejecuta en un contenedor, consume una cantidad significativa de memoria simplemente por la existente. CPU sobrecargado Naturalmente, toda esta comunicación interprocesal e intercontenedor requiere recursos de computación. Base de datos Overhead Las transacciones normales son imposibles cuando las operaciones abarcan múltiples microservicios. Las transacciones distribuidas son mucho más lentas y requieren una coordinación compleja, a menudo manual. Dispositivos de Red Disc Overhead Los contenedores de microservicio a menudo se ejecutan en discos montados en red, lo que aumenta la latencia, reduce el rendimiento (IOPS) y lo hace impredecible. Proyecto Borders Overhead El diseño y desarrollo de microservicios trae dificultades en la evolución y refactorización de un proyecto. No es fácil cambiar la zona de responsabilidad de un servicio. No puedes simplemente cambiar el nombre o borrar algo.No puedes simplemente mover el código de un servicio a otro. Esto generalmente requiere: Mucho tiempo y esfuerzo, varias versiones de API, y migraciones complejas antes de que la funcionalidad pueda redistribuirse entre los servicios. Además, si desea actualizar o reemplazar una biblioteca, tendrá que hacerlo en todos los proyectos, no solo uno. Infraestructura superior No puedes simplemente “hacer microservicios”. necesitarás infraestructura – no, INFRASTRUCTURA: contenedores (cada uno que contiene copias de bibliotecas compartidas), las cubiertas, servicios en la nube, las colas (RabbitMQ, Kafka) herramientas de sincronización de configuración (Zookeeper, Etcd, Consul), y así sucesivamente. Todo esto requiere enormes recursos tanto de las máquinas como de las personas. Desarrollo independiente Overhead Apoyar el despliegue independiente significa: Cada servicio debe ser desplegable por separado, Cada una de ellas debe tener su propia tubería CI/CD. y la parte más difícil - API versioning. Cada servicio tendrá que soportar varias versiones de la API simultáneamente y los llamadores tendrán que rastrear estas versiones y actualizar sus llamadas a tiempo. Bolas de mudo distribuidas Hay una probabilidad de casi 100% de que no obtenga sus límites de servicio desde el principio.En lugar de microservicios limpios, acabará con una bola de barro distribuida, donde la funcionalidad está mal distribuida, las llamadas externas desencadenan cadenas enteras de llamadas de servicio interno, y todo es terriblemente lento. ¿Es el monolito realmente tan aterrador? Monolitos Modulares Los monolitos modulares le permiten evitar la mayor parte del servicio de microservicio, al tiempo que proporcionan separación que puede usarse más tarde si es necesario. Este enfoque implica escribir la aplicación (principalmente el backend) como un único servicio dividido en módulos individuales con: límites claramente definidos, y interdependencia mínima. Esto hace posible dividirlos en servicios si la escalación realmente lo requiere. Espera, ¿puedes hacer eso? Muchos beneficios atribuidos a la arquitectura de microservicios se pueden lograr en un monolito: La modularidad se puede implementar con características de lenguaje: clases, nombres, proyectos y asambleas. Bases de datos múltiples – posible, si realmente es necesario; Idiomas múltiples – también posible, por ejemplo, combinar C/C++/C#/Java con lenguajes de scripting como JavaScript, Python o Erlang para el desarrollo de nivel superior; Interop — muchas plataformas soportan la llamada de C/C++ desde Java, C#, Python, JavaScript o Erlang; Colas de mensajes: sólo use la estructura de datos adecuada. Y cuando desea deshabilitar - una tecla, y toda la aplicación está a tu alcance. Actor Frameworks Frameworks de actores le permiten construir microservicios - sin los microservicios. Toda la lógica se divide en clases (actores) que se comunican sólo a través de un bus de mensajes (cadenas). Estos actores pueden: existe dentro de un único proceso, o distribuidos a través de varios procesos. De esta manera, se obtiene el modelo de programación de microservicios, pero la mayor parte de la infraestructura es manejada por el marco mismo. Conclusion Conclusión La arquitectura debe ser elegida basándose en: Requisitos del proyecto, los recursos disponibles, y la experiencia del equipo. Son útiles para grandes proyectos y equipos, pero el monolito no es obsoleto y no es una deuda técnica por defecto. Lo que más importa es el equilibrio entre flexibilidad y complejidad, escalabilidad y mantenimiento, para que el sistema que construyes sea eficaz y sostenible.