Microservicios y monolito
Qué es un microservicio, qué se gana y qué se paga al partir una aplicación en muchos, cómo se decide dónde poner el corte y de qué formas se hablan entre sí los servicios resultantes.
Qué es un microservicio
Un microservicio es un servicio que se despliega por su cuenta, sin arrastrar a los demás, y que está modelado alrededor de una parcela del negocio. Visto desde fuera es una caja negra: tiene una función definida, se le pide algo y produce un resultado, y nadie que lo use necesita saber cómo está hecho por dentro.
- Se despliega de forma independiente: se puede publicar una versión nueva de uno sin tocar el resto.
- Se modela alrededor de un dominio de negocio, no alrededor de una capa técnica.
- Está muy débilmente acoplado con los demás, y su granularidad es fina: poca responsabilidad cada uno.
- Se comunican con protocolos ligeros, típicamente sobre HTTP.
- Cada uno lo puede desarrollar un equipo distinto, en un lenguaje distinto y con una base de datos distinta.
- Aporta resiliencia: si uno falla, no se viene abajo la aplicación entera.
El prefijo «micro» induce a error y conviene desactivarlo cuanto antes: no significa que el servicio tenga que ser pequeño en líneas de código. El tamaño lo dicta la funcionalidad que presta, y un servicio que atienda un dominio complejo será grande sin dejar de ser un microservicio. Lo que tiene que ser pequeño es su responsabilidad, no su código.
En cuanto a su parentesco, un microservicio es un tipo de servicio de los que describe la arquitectura orientada a servicios, llevado al extremo de la granularidad fina y del despliegue independiente. La SOA clásica, el ESB y los servicios web se estudian en el tema de servicios web del bloque de Desarrollo; aquí interesa lo que viene después, que es cómo se despliegan y se explotan.
No todo funciona mejor con microservicios. Es una arquitectura que resuelve problemas de escala organizativa y técnica, y que en un sistema pequeño solo añade coste.
Para el examen
Responsabilidad: una sola por servicio
Datos: su propia base de datos
Despliegue: independiente
Lo que rompe la arquitectura: compartir base de datos
El monolito y sus límites
La alternativa frente a la que se define esta arquitectura es el monolito: una única aplicación que contiene toda la funcionalidad, se compila entera, se despliega entera y se ejecuta como un solo proceso. Un monolito no es un mal diseño: es el punto de partida razonable de casi cualquier sistema, y mientras el equipo sea pequeño y el dominio manejable es la opción más eficiente que existe.
Los problemas aparecen con el tamaño. Un cambio en una esquina obliga a volver a desplegar todo el sistema; para escalar la parte que se satura hay que replicar la aplicación completa aunque el resto esté ociosa; un fallo de memoria en un módulo secundario tumba el proceso entero; y todos los equipos compiten por el mismo calendario de publicación.
| Aspecto | Monolito | Microservicios |
|---|---|---|
| Despliegue | Todo o nada | Cada servicio por separado |
| Escalado | Se replica la aplicación entera | Se replica solo el servicio que lo necesita |
| Tecnología | Una sola pila para todo | Cada servicio puede usar la suya |
| Fallo | Se lleva por delante toda la aplicación | Queda acotado, si el diseño lo prevé |
| Comunicación interna | Llamadas dentro del mismo proceso: rápidas y fiables | Llamadas por red: lentas y falibles |
| Datos | Una base de datos con transacciones ACID | Una base por servicio, sin transacción global |
| Equipos | Coordinados en un calendario común | Autónomos, cada uno con el suyo |
| Operación | Un proceso que vigilar | Decenas de procesos, con orquestador y observabilidad |
El coste de los microservicios es que convierten llamadas internas de función, que nunca fallaban, en llamadas de red, que fallan. Todo lo complicado de esta arquitectura sale de ahí.
Para el examen
Sus dos límites: se despliega entero por un cambio pequeño y solo escala completo
Cuándo es la opción sensata: mientras el equipo y el dominio sean pequeños
Los retos que introduce la arquitectura
Partir un sistema en servicios independientes no elimina la complejidad: la traslada del interior del código al espacio entre los servicios. Estos son los frentes que se abren y que hay que atender desde el primer día.
| Reto | En qué consiste |
|---|---|
| Despliegue independiente | Cada servicio tiene que poder publicarse solo, lo que exige automatizar la construcción y la entrega. |
| Escalado independiente | Cada servicio crece por su cuenta, y hay que saber cuál necesita crecer. |
| Distribución de la responsabilidad | Decidir qué le toca a cada servicio y que nadie invada el terreno de otro. |
| Acoplamiento y cohesión | Buscar que cada servicio sea cohesionado por dentro y esté poco atado a los demás. |
| Mezcla de tecnologías | La libertad de elegir lenguaje y base de datos por servicio se paga en conocimiento y en mantenimiento. |
| Gobernanza | Administrar muchos servicios es complejo, y de ahí salen los orquestadores y los patrones de diseño propios de esta arquitectura. |
A esos retos de diseño se suman los problemas que aparecen ya en explotación, y que son consecuencia directa de haber puesto una red por medio: latencia en cada llamada, fallos de red que antes no existían, consistencia de datos entre servicios que ya no comparten transacción, sobrecarga de operaciones, dificultad para averiguar dónde ha fallado algo, y una cantidad de decisiones tecnológicas que hay que tomar sin tener toda la información.
La consecuencia organizativa que se pregunta menos y pesa más: los microservicios exigen equipos autónomos con capacidad de desplegar por su cuenta. Sin esa autonomía, se paga toda la complejidad técnica y no se cobra ninguna de las ventajas.
Para el examen
Qué se cambia al repartir: complejidad de programación por complejidad de operación
Qué aparece: red, latencia, coherencia de datos y despliegues
Dónde cortar: DDD y Bounded Context
La decisión más difícil de esta arquitectura no es técnica: es dónde se pone el corte entre un servicio y el siguiente. Cortar mal produce lo peor de los dos mundos, servicios que no se pueden desplegar sin coordinar y que se llaman entre sí continuamente. La disciplina que se usa para decidirlo es el diseño dirigido por el dominio, DDD, que consiste en descubrir los conceptos del negocio mirándolos desde varios puntos de vista y traducirlos después en servicios, entidades y repositorios.
Su herramienta concreta es el Bounded Context, o contexto delimitado: un patrón que divide el modelo grande en submodelos especializados por áreas, cada uno con su propio vocabulario y sus propias reglas. A cada microservicio le corresponde un contexto, es decir, una funcionalidad o un área del negocio.
Lo que aporta el contexto delimitado es permitir que un mismo nombre signifique cosas distintas en sitios distintos sin que eso sea una contradicción. En la plataforma, «alumno» en el contexto de matriculación son sus datos personales, su plan contratado y su forma de pago; en el contexto de estudio, ese mismo alumno es su progreso, sus subtemas cerrados y sus preguntas falladas. Intentar un único modelo de alumno que valga para los dos produce una entidad enorme que ninguno de los dos equipos puede cambiar sin romperle algo al otro.
Es mejor segregar. Dos modelos pequeños y especializados por área, aunque compartan nombres, mantienen mucho mejor que uno grande que intente servir a todos.
Para el examen
Por dónde se corta: por dominio de negocio, no por capa técnica
Qué marca la frontera: el contexto delimitado del diseño dirigido por el dominio
Cómo se comunican: síncrono frente a asíncrono
En comunicación síncrona el servicio que llama se queda esperando la respuesta y no puede hacer nada mientras tanto. Es la forma más natural de programar y la más fácil de entender, pero tiene un defecto grave a escala: encadena la disponibilidad. Si A espera a B y B espera a C, la fiabilidad del conjunto es la del eslabón más débil, y la lentitud de uno solo se propaga hasta el usuario.
En comunicación asíncrona quien llama no espera: deja el mensaje y sigue trabajando. El destinatario lo recogerá cuando pueda, y si está caído el mensaje esperará hasta que vuelva. Eso desacopla a los servicios en el tiempo, que es la única manera de que la caída de uno no arrastre a los demás.
| Modo asíncrono | Cómo funciona |
|---|---|
| Petición y respuesta | Se apoya en colas: se deja la petición en una cola y la respuesta llega por otra. Es transaccional y da entrega garantizada. |
| Dirigido por eventos | Un servicio publica un evento con información de algo que ha ocurrido, y quienes estén suscritos lo usan como disparador de su propio trabajo. |
| Datos compartidos | Se deja el dato en un sitio común (un volumen, un almacenamiento de objetos, una base de datos) y se avisa a los interesados para que lo consuman cuando lo necesiten. Es el menos habitual. |
En cuanto al transporte concreto, la lista es la conocida: REST sobre HTTP, gRPC sobre HTTP/2 con Protocol Buffers, GraphQL como agregador de consultas, SOAP donde lo exige la normativa de interoperabilidad, y RMI en entornos exclusivamente Java. Todos ellos están explicados en el tema de servicios web del bloque de Desarrollo, así que aquí basta con saber que REST y gRPC son hoy los dos más usados entre microservicios, y que gRPC gana cuando la llamada es interna y el rendimiento importa.
Elegir síncrono por comodidad es la decisión que más sistemas de microservicios ha hecho fracasar: convierte una arquitectura distribuida en un monolito repartido, con todos los inconvenientes de los dos.
Para el examen
Síncrono (REST, gRPC): acopla al que llama con el que responde
Asíncrono con cola: desacopla y aguanta caídas
Su precio: solo da coherencia eventual
Brokers de mensajes y arquitectura dirigida por eventos
La pieza que hace posible la comunicación asíncrona es el broker de mensajes: un intermediario al que un servicio entrega el mensaje y del que otro lo recoge, de modo que los dos nunca llegan a hablarse directamente. El broker se responsabiliza de guardar el mensaje hasta que alguien lo consuma, de garantizar que se entrega y de mantener el orden cuando hace falta.
| Forma | Cuántos lo reciben | Uso típico |
|---|---|---|
| Cola | Un solo consumidor recibe cada mensaje, aunque haya varios escuchando. | Repartir trabajo entre copias del mismo servicio. |
| Topic | Todos los suscritos reciben una copia del mensaje. | Avisar de que ha ocurrido algo a cuantos les interese. |
Sobre los topics se monta la arquitectura dirigida por eventos, que invierte la dirección de la dependencia y es la diferencia de fondo con la comunicación por petición. En el modelo clásico, el servicio de matriculación tiene que saber a quién avisar: llama al de facturación, al de correo y al de estadística, y cada vez que aparece un nuevo interesado hay que modificarlo. En el modelo por eventos, el servicio de matriculación publica que se ha matriculado un alumno y se desentiende; quien quiera enterarse se suscribe, y añadir un consumidor nuevo no obliga a tocar al emisor.
Los productos que se citan como brokers son Apache Kafka, RabbitMQ, Apache ActiveMQ y los servicios gestionados de las nubes públicas. Kafka, en particular, funciona más como un registro ordenado y duradero de eventos que como una cola tradicional, lo que permite que un consumidor nuevo se lea desde el principio todo lo que ya había pasado.
Cola y topic no son sinónimos y se preguntan. En una cola cada mensaje lo procesa un consumidor; en un topic lo reciben todos los suscritos.
Para el examen
Los dos nombres: RabbitMQ y Kafka
En arquitectura dirigida por eventos: quien publica no sabe quién le escucha