Microservicios en la práctica: problemas reales y cómo resolverlos
By Tomás Hernández, Posted on January 15, 2026 (1mo ago)
¿Qué vas a aprender acá?
Al terminar este post vas a entender:
- Por qué migrar de monolito a microservicios no es gratis (ni fácil) y qué nuevos problemas aparecen al hacerlo.
- Cómo se comunican los microservicios y cuándo usar Request-Response o Event-Driven.
- Qué limitaciones tiene el modelo síncrono y en qué escenarios una arquitectura Event-Driven es necesaria.
- Qué pasa cuando tenés muchos microservicios y clientes acoplados, y cómo un API Gateway resuelve ese problema.
- Qué sucede cuando un microservicio recibe mucho tráfico, y cómo escalarlo usando Load Balancers y Service Discovery.
- Por qué la consistencia se vuelve un problema distribuido, y cómo el patrón Saga permite manejarla sin transacciones globales.
- Por qué debuggear microservicios es difícil, y cómo la observabilidad permite entender qué está pasando en producción.
Conceptos importantes antes de empezar
Monolito
Una aplicación monolítica es aquella donde toda la lógica de negocio, el backend y el manejo de la base de datos están en una misma aplicación (arquitectura de tres niveles).
Microservicio
Un microservicio es un servicio independiente que tiene su propia responsabilidad y puede ser desplegado de forma individual. El sistema completo se organiza como una colección de estos servicios poco acoplados.
Event-Driven architecture
Arquitectura dirigida por eventos que establece comunicación asíncrona basada en eventos entre microservicios, permitiendo mayor desacoplamiento y escalabilidad.
Sabiendo estas definiciones podemos empezar.
Motivación: ¿Por qué microservicios?
Los microservicios son la arquitectura más moderna, actual y popular en la industria. Este tipo de arquitectura es fundamental en muchas empresas grandes como Amazon, Google, Netflix, Meta, Uber, Airbnb, etc.
Cuando los microservicios se implementan bien, permiten a las organizaciones:
- Escalar rápidamente: Tanto a nivel organizacional como del sistema.
- Alcanzar millones de usuarios: Con la capacidad de escalar componentes específicos según necesidad.
- Mantener bajos los costos operacionales: Al poder optimizar recursos por servicio.
- Ser eficientes e innovar: Permitiendo que equipos trabajen de forma independiente.
Importante: La idea de usar microservicios y escalar rápido puede ser motivador, pero muchas organizaciones los implementan mal y deshacen la decisión de migrar. Si se aplican bien (y en el momento adecuado) puede ser muy buena decisión
Hay un dicho que dice que si tu equipo puede ser alimentado por 2 pizzas, entonces podés seguir usando arquitectura monolítica. Esto nos da una idea de cuándo considerar migrar a microservicios.
Problema: Las limitaciones de la arquitectura monolítica
En una aplicación monolítica, la lógica de negocio, el desarrollo del backend y el manejo de la base de datos está en una misma aplicación.
Este tipo de arquitectura tiene muchas ventajas y es por eso que hoy en día se sigue utilizando, especialmente en startups y equipos pequeños.
Ventajas del monolito
- Fáciles de diseñar: Se acopla a cualquier sistema web, sea cual sea el tipo del negocio.
- Fácil de implementar: Los desarrolladores no tienen que romperse la cabeza. Usan tecnologías que conocen y podemos tener fácilmente un sistema funcional.
Desventajas del monolito
Sin embargo, a medida que el sistema crece, aparecen problemas significativos:
1. Poca escalabilidad organizacional
Al haber tantos desarrolladores en un mismo codebase, se hace común ver problemas de MRs (Merge Requests), muchos conflictos y otros problemas.
Cuando el equipo crece, la coordinación se vuelve cada vez más difícil y costosa.
2. Código complejo
A medida que agregamos código se hace más grande y complejo. Esto produce que:
- Sea más difícil de razonar sobre él.
- El IDE tarde más en cargar.
- Es más lento de buildear y testear.
- Más riesgos para el deploy.
- Features más largas y por ende, menos deploys.
- El onboarding a nuevos desarrolladores se complejiza.
3. Poca escalabilidad del sistema
Cada instancia de aplicación que contiene toda la lógica requiere más CPU y memoria. Tenemos que correr cada instancia en computadoras más caras.
También es más difícil de migrar algunas tecnologías viejas. Cualquier bug pequeño o de rendimiento afecta a toda la aplicación y nos obliga a hacer un redeploy entero (o rollbacks).
4. Estamos atados a un mismo lenguaje y tecnologías
Esto no suele ser bueno porque hay algunos problemas que pueden ser resueltos de manera más clara y óptima en otros lenguajes (o incluso paradigmas)
Ej. 1: Servicios de Inteligencia Artificial
Imaginemos que tenés una aplicación de e-commerce escrita en TypeScript/Node.js.
Querés agregar funcionalidades de IA como:
- Recomendaciones personalizadas de productos
- Análisis de sentimiento en reviews
- Detección de fraudes con machine learning
- Procesamiento de imágenes para búsqueda visual
En un monolito, tendrías que implementar todo esto en TypeScript, lo cual es problemático porque:
- Las librerías de machine learning más potentes (TensorFlow, PyTorch, scikit-learn) están principalmente en Python.
- Python tiene un ecosistema mucho más rico para IA/ML con miles de librerías especializadas.
- El procesamiento numérico en Python con NumPy es significativamente más rápido que en JavaScript.
- La comunidad de IA/ML está principalmente en Python.
Si intentás hacer esto en TypeScript, terminarías:
- Reimplementando funcionalidades que ya existen en Python.
- Usando bindings de JavaScript a librerías de Python (lo cual es lento y complicado).
- O simplemente no pudiendo implementar ciertas funcionalidades por falta de herramientas.
Ej. 2: Análisis de Datos y Big Data
Servicios que procesan grandes volúmenes de datos se benefician de:
- Python con Pandas, Dask, o PySpark para análisis de datos.
- Scala/Java para procesamiento distribuido con Apache Spark.
- R para análisis estadísticos avanzados.
TypeScript simplemente no tiene el ecosistema ni el rendimiento para estas tareas.
El problema real: En un monolito, si tu aplicación principal está en TypeScript, estás forzado a usar TypeScript para todo, incluso cuando hay herramientas mucho mejores disponibles en otros lenguajes. Esto te limita en lo que podés construir y te hace más lento de lo que necesitás ser. siendo un solo deployable.
¿Qué son los microservicios?
Los microservicios organizan la lógica empresarial como una colección de servicios poco acoplados y desplegados individualmente.
Cada servicio pertenece a un pequeño equipo y tiene un ámbito de responsabilidad limitado.
En otras palabras, en lugar de tener un único monolito gigante, dividís tu aplicación en piezas independientes que pueden evolucionar, escalar y fallar de manera aislada.
¿Cuándo Microservicios es la solución correcta?
Microservicios es la solución cuando necesitás resolver problemas de escalabilidad organizacional y del sistema que otras arquitecturas no pueden manejar
- Escalabilidad organizacional: Cuando tu equipo crece y necesitás que múltiples equipos trabajen de forma independiente sin pisarse entre sí.
- Escalabilidad del sistema: Cuando diferentes partes de tu aplicación tienen distintas necesidades de recursos, tráfico o tecnologías.
- Independencia de despliegue: Cuando necesitás desplegar y escalar componentes individuales sin afectar al resto del sistema.
- Flexibilidad tecnológica: Cuando diferentes partes de tu aplicación se benefician de distintos lenguajes o tecnologías. Esta es una de las ventajas más poderosas de los microservicios.
Ventajas de los microservicios
1. Escalabilidad organizativa mayor
Cada servicio contiene un subconjunto de la funcionalidad global, por lo que el codebase de cada servicio es menor. Esto permite que:
- El código cargue más rápido en un IDE.
- Sea fácil testear cada servicio y entender qué hace.
- El onboarding sea más rápido para engineers que lo mantengan.
- Los equipos trabajen más rápido en su “mundo propio”.
2. Escalabilidad del sistema más alta
En un monolito, cada servidor tiene toda la aplicación, lo que conlleva un costo más alto de mantenimiento.
En microservicios:
- Cada instancia es más chica, consume menos memoria y CPU, y puede correrse en servidores más baratos.
- Cada microservicio puede ser desarrollado en el lenguaje más adecuado para su dominio, facilitando refactorizaciones o cambios tecnológicos sin afectar al resto.
- Mayor estabilidad: si un microservicio falla, podemos levantar más instancias rápidamente sin esperar un deploy de todo el monolito.
Nota práctica: normalmente varios microservicios corren como contenedores en el mismo servidor. Cada microservicio puede tener límites de CPU y memoria distintos según lo necesite: uno con 2GB de RAM, otro con 4GB, y así sucesivamente. Esto permite ajustar los recursos de manera fina y eficiente sin repetir lo que ya explicamos sobre escalabilidad.
Desafíos de los microservicios
Los microservicios no son una solución mágica. Traen sus propios desafíos
1. Sistema distribuido
Los microservicios son un gran sistema distribuido. En la arquitectura monolítica tenemos un comportamiento, éxito y rendimiento predecible pues cuando llamamos a algo que está dentro del mismo sistema es sencillo de trackear.
En los microservicios esto no sucede, el comportamiento, éxito y rendimiento no es tan predecible porque la comunicación es entre computadoras diferentes. Suele haber latencia, pérdida de paquetes o inclusive errores.
2. Testing
No hay garantía de que cuando todos los servicios estén en producción funcionen entre ellos (integration tests). Lo complicado es saber qué microservicio es el responsable de hacer esos tests de integración.
3. Dificultad de monitorear rendimiento y bugs
Si un cliente hizo una solicitud para hacer X cosa pero esa X cosa necesita comunicarse con 10 microservicios para responder es muy difícil de trackear qué sucede si algo falla.
Puede suceder que:
- La información no llegue.
- La información sea incorrecta.
- La información tarda demasiado tiempo en llegar.
4. Dificultad en la separación de responsabilidades
Si las responsabilidades de los microservicios están mal distribuidas podemos tener problemas organizacionales. Si un cambio en un microservicio conlleva a hablar con otros equipos hay algo raro (cada equipo debería funcionar por sí solo).
Importante: Si estos puntos no se tienen en cuenta, en vez de armar una arquitectura de microservicios habremos construido un "monolito distribuido".
Comunicación entre microservicios
Existen dos modelos principales de comunicación entre microservicios, que se diferencian principalmente por si el emisor espera o no una respuesta inmediata.
Request-Response Model
Es el modelo síncrono, donde un servicio realiza una petición (generalmente HTTP) a otro servicio y espera la respuesta para continuar su ejecución.
Características
- Comunicación síncrona: el Sender envía una petición y debe esperar a que el Receiver responda.
- Bloqueo temporal: si la respuesta no llega (por caída o lentitud del Receiver), el Sender queda bloqueado hasta que ocurra un timeout.
- Acoplamiento: el Sender necesita conocer exactamente quién es el Receiver, cómo es su API y dónde está ubicado.
Casos de uso
- Cuando el usuario necesita la respuesta inmediatamente (ej.: cargar los productos antes de renderizar una página).
- Cuando la interacción es simple y directa, y no justifica el costo adicional de mantener un message broker, manejar eventos, lidiar con consistencia eventual, etc.
Event-Driven Architecture
Este modelo se basa en una comunicación asíncrona orientada a eventos.
Un servicio publica un evento y uno o más servicios reaccionan a él, sin que exista una llamada directa entre ellos.
Es un enfoque muy común en arquitecturas de microservicios, ya que permite mayor desacoplamiento y escalabilidad.
Características:
- Comunicación asíncrona: el Producer publica un evento y no espera ninguna respuesta.
- Inversion of Control: el Producer no controla ni necesita conocer qué servicios consumirán el evento.
- Loose Coupling: los servicios están desacoplados tanto a nivel estructural como temporal.
- Uno a muchos: un mismo evento puede ser consumido por múltiples Consumers.
Ventajas sobre Request-Response:
- El Producer puede continuar procesando su siguiente tarea en lugar de esperar una respuesta que tal vez no necesita.
- El Producer no necesita conocer todos los servicios que consumirán el evento.
- Se logra un mayor desacoplamiento entre servicios, facilitando la escalabilidad y la evolución del sistema.
¿Cuándo usar cada uno?
En la práctica, una arquitectura de microservicios no elige uno u otro, sino que combina ambos modelos:
- Event-Driven Architecture
- Synchronous Request-Response Model
Una buena regla es:
- Empezar con Request-Response, por su simplicidad y menor costo operativo.
- Evolucionar hacia Event-Driven únicamente cuando sea necesario:
- mayor escalabilidad,
- menor acoplamiento,
- procesamiento asíncrono,
- tolerancia a fallos.
Casos de uso para Event-Driven Architecture
1. Fire and Forget
Se utiliza cuando el cliente no espera una respuesta, o bien no necesita que la respuesta sea inmediata.
Ej.:
- Respuesta no inmediata: generar un reporte pesado cuyo tiempo de procesamiento es desconocido. El sistema inicia el proceso y notifica al usuario cuando el reporte está listo.
- Sin respuesta: cuando un usuario deja una reseña en un producto. Al usuario solo le importa que la acción se haya registrado, no recibir una confirmación posterior.
2. Entrega confiable
Aplica cuando no nos podemos permitir perder eventos o acciones. Ej.:
- En transacciones financieras, ningún mensaje puede perderse.
- Si un usuario paga un producto pero el servicio de entregas no es notificado debido a una caída, el sistema debe reintentar el envío del evento hasta garantizar que sea recibido.
3. Flujo continuo de eventos (alta frecuencia)
En escenarios como ubicación en tiempo real o datos de sensores, se generan grandes volúmenes de eventos por segundo, por lo que no es viable bloquear ni procesar cada evento inmediatamente.
Enfoque: recibir los eventos, encolarlos y procesarlos posteriormente.
4. Detección de anomalías y reconocimiento de patrones
Los eventos permiten monitorear el comportamiento del sistema.
Ej.: Si el message broker deja de recibir eventos, puede indicar un problema en los Producers, lo que permite detectar fallos de forma temprana.
5. Broadcasting
Se utiliza cuando un evento debe ser difundido a múltiples servicios, sin que el cliente que originó la acción tenga conocimiento de los efectos secundarios.
Ej.: En sistemas de publicidad, al recibir un click, el AdService publica un evento que es consumido por múltiples servicios (facturación, métricas, analytics), sin impactar en la experiencia del usuario.
6. Buffering
Permite absorber picos de tráfico mediante un message broker, evitando sobrecargar los servicios consumidores.
Ej.: En una red social, si un post se vuelve viral y recibe millones de interacciones simultáneas, el message broker actúa como buffer:
- recibe todos los eventos,
- los encola,
- y los distribuye gradualmente a servicios como PostsService y CommentsService según su capacidad de procesamiento.
Este enfoque garantiza que los eventos no se pierdan y que los servicios no colapsen ante picos de demanda.
Patrones de Event-Driven architecture
Event-Streaming
En este patrón, el message-broker es utilizado como almacenamiento temporal o permanente para eventos.
Los consumers tienen full-access a los logs de esos eventos, incluso si ya fueron consumidos por el mismo consumer o por otros.
Este patrón es una gran elección para los siguientes casos de uso:
- Reliable delivery (entrega segura): Debido a que el message-broker o bien tiene los eventos indefinidamente o bien los tiene durante un largo periodo de tiempo tal que nos permite acceder a esos eventos y auditarlos si fuese necesario.
- Pattern / Anomaly detection: Pues el consumer necesita acceso a todos los eventos pasados en una ventana concreta.
Pub/Sub
En este patrón, los Consumers se suscriben a una queue particular o canal para recibir nuevos eventos luego de subscribirse.
En este caso, los subscriptores no tienen acceso a eventos viejos, y tan pronto como los subscriptores actuales reciben el evento, el message-broker lo borrará de su queue.
Este patrón es una gran elección para los siguientes casos de uso:
- El message broker está siendo utilizado como un almacenamiento temporal o como mecanismo de broadcasting: Luego de que los suscriptores consumen los eventos, estos típicamente son transformados y almacenados permanentemente en una base de datos o son pasados a otro servicio.
- Fire and Forget
- Broadcasting
- Buffering
- Infinite stream of events
Semántica de entrega de mensajes
Existen tres tipos de semántica de entrega
At Most Once
El mensaje se entrega cero o una única vez. Puede perderse, pero nunca se duplica.
Casos de uso: Información que no es crítica si se pierde (ej.: actualizaciones de ubicación en tiempo real de un dispositivo IoT).
At Least Once
El mensaje se entrega al menos una vez. Puede duplicarse, pero nunca se pierde.
Casos de uso: Eventos críticos que no podemos permitirnos perder (ej.: notificaciones de mal funcionamiento de un dispositivo).
Exactly Once
El mensaje se entrega exactamente una vez. No se pierde ni se duplica.
Casos de uso: Transacciones financieras donde debemos procesar el pago una y solo una vez.
Problemáticas comunes en arquitecturas de microservicios
A medida que un sistema crece y se descompone en cada vez más microservicios, comienzan a aparecer nuevos desafíos que no existen en arquitecturas monolíticas.
Problema: ¿Qué pasa si tengo muchos microservicios?
En una arquitectura de microservicios, cada servicio tiene su propia lógica, su propia API y su propia URL o IP.
Si un cliente tuviera que comunicarse directamente con cada microservicio, surgirían varios problemas:
- El cliente debería conocer todas las URLs de los microservicios.
- Un cambio interno (endpoint, versión, ubicación) obligaría a modificar al cliente.
- El cliente tendría que manejar:
- autenticación,
- autorización,
- retries,
- rate limiting,
- versionado,
- y fallos parciales.
Esto genera un alto acoplamiento entre el cliente y la arquitectura interna
Solución: API Gateway
Para resolver este problema, se introduce un API Gateway.
El API Gateway actúa como un punto de entrada único al sistema.
¿Cómo funciona?:
- El cliente se comunica solo con el API Gateway.
- El Gateway se encarga del resto como redirigir la request al microservicio correspondiente,
Desde la perspectiva del cliente: existe una única API, independientemente de cuántos microservicios haya detrás.
Ventajas:
- Desacopla al cliente de la estructura interna del sistema.
- Simplifica la lógica del cliente. No tiene que conocer todos los microservicios.
- Centraliza las soluciones a problemas transversales como rate limiting, logging, caching.
Problema: Escalabilidad y alto tráfico
Otro desafío típico aparece cuando un microservicio recibe mucho más tráfico que los demás.
¿Qué pasa si un microservicio no aguanta el tráfico? Si un servicio comienza a recibir una gran cantidad de requests la instancia puede saturarse, aumentar la latencia, o directamente caerse.
Solución: Load Balancer
La solución es escalar horizontalmente, levantando múltiples instancias del mismo microservicio.
Para distribuir el tráfico entre múltiples instancias, se utiliza un Load Balancer.
¿Qué hace un Load Balancer?
- Recibe las requests entrantes
- Las distribuye entre varias instancias del mismo servicio
- Evita que una sola instancia se sobrecargue
Ventajas:
- Alta disponibilidad: si una instancia cae, el tráfico se redirige a las restantes
- Mejor performance: las requests se reparten equitativamente
- Escalabilidad: se pueden agregar o quitar instancias según la demanda
Flujo: Cliente → API Gateway → Load Balancer → Instancias del Microservicio
Importante: En arquitecturas de microservicios, no solo importa cómo se comunican los servicios entre sí, sino también cómo acceden los clientes y cómo escala el sistema ante el tráfico.
El API Gateway resuelve el problema de acceso y desacoplamiento del cliente, mientras que el Load Balancer permite escalar y distribuir carga de forma eficiente.
Problema: Riesgos de cambios en microservicios
A diferencia de un monolito:
- no existe un deploy único,
- no se puede asumir que todos los consumidores se actualizan al mismo tiempo,
Esto genera varios problemas:
- romper consumidores existentes,
- generar fallos difíciles de detectar,
- forzar deploys coordinados (volviendo al acoplamiento del monolito).
Solución: Versionado y compatibilidad hacia atrás
Para evitar estos problemas, las APIs deben diseñarse con backward compatibility
Esto implica:
- evitar cambios breaking en endpoints existentes (la cantidad de veces que sufrí con esto),
- agregar campos en lugar de modificar o eliminar los actuales,
- tolerar datos desconocidos o faltantes.
Cuando un cambio incompatible es inevitable, se introduce versionado explícito.
Ej. comunes de versionado:
- Versionado en la URL: /v1/orders, /v2/orders
- Versionado por headers
- Versionado gestionado desde el API Gateway
Importante: el versionado muchas veces es la salida fácil, pero a veces se hace medio denso de mantener.
Problema: Comunicación entre servicios
En microservicios, los servicios no son entidades estáticas:
- las instancias crecen por sí mismas
- se reinician
- cambian de IP
Esto vuelve impracticable cualquier forma de configuración estática.
Si un servicio necesita comunicarse con otro:
- ¿a qué IP se conecta?
- ¿qué pasa si esa instancia cae?
- ¿cómo sabe cuántas instancias existen en ese momento?
Hardcodear direcciones o URLs no escala, es fácil que falle y que rompe con el principio de despliegue independiente.
La solución: Service Discovery
El Service Discovery permite que los servicios se encuentren dinámicamente entre sí.
El flujo general es:
- Cada instancia se registra en un service registry al iniciar.
- Los clientes consultan el registry para descubrir instancias disponibles.
- El tráfico se enruta solo a instancias saludables.
Este mecanismo permite:
- escalar servicios sin cambiar configuraciones,
- tolerar fallos de instancias individuales,
- mantener la comunicación desacoplada de la infraestructura.
En plataformas modernas, como Kubernetes, el service discovery suele estar integrado:
- DNS interno,
- objetos Service,
- balanceo automático.
Problema: Consistencia distribuida en microservicios
En una arquitectura monolítica, la consistencia no suele ser un problema.
En una arquitectura de microservicios, la consistencia se vuelve un problema.
Cada microservicio:
- tiene su propia base de datos,
- maneja su propio estado,
- se desplega y escala de manera independiente.
Esto implica que no existe una transacción global que garantice que todos los cambios ocurran juntos.
Cuando una operación involucra múltiples microservicios, pueden ocurrir fallos o inconsistencias.
Ej.:
- Se crea un pedido de X del producto Y.
- Se reserva Y para el pedido X.
- Se procesa el pago.
- Se coordina el envío.
¿Qué pasa si el pago falla luego de haber reservado stock? ¿O si el envío falla después de cobrar?
El sistema puede quedar en un estado inconsistente, donde algunas acciones se completaron y otras no.
Consistencia eventual
En microservicios, el sistema no siempre está consistente en todo momento, pero eventualmente llega a un estado consistente.
Esto significa aceptar que:
- los datos pueden estar temporalmente desincronizados,
- distintos servicios pueden ver distintos estados del sistema (diuh),
- la consistencia fuerte es la excepción (y no es una regla!).
Este cambio de paradigma es clave para entender por qué aparecen patrones como Saga.
Solución: Patrón Saga
El patrón Saga surge como una solución al problema de la consistencia distribuida.
Una Saga modela una operación larga como una secuencia de pasos:
- cada paso es una transacción local,
- cada transacción tiene una acción compensatoria asociada.
¿Cómo funciona una Saga?
Si todos los pasos se completan, la operación finaliza con éxito.
Si algún paso falla, se ejecutan las acciones compensatorias (yo las veo como la inversa) para deshacer los efectos previos.
Ej.:
- Crear orden, si falló: cancelás orden
- Reservar stock, si falló: liberás el stock
- Procesar pago, si falló: reembolsás el pago
De esta forma, el sistema puede volver a un estado consistente sin necesidad de locks globales.
Tipos de Saga
Saga basada en Choreography
- No hay un coordinador central.
- Los servicios reaccionan a eventos.
- Cada servicio decide cuál es el próximo paso.
Ventajas:
- Mayor desacoplamiento.
- Arquitectura más distribuida.
Desventajas:
- Flujo difícil de seguir.
- Debugging complejo a gran escala.
Saga basada en Orchestration
- Existe un orquestador que controla el flujo.
- El orquestador decide qué servicio ejecutar y cuándo.
Ventajas:
- Flujo explícito y fácil de entender
- Mejor control de errores
Desventajas:
- Mayor acoplamiento.
- El orquestador puede convertirse en un punto crítico.
Tradeoffs del patrón Saga
- Mayor complejidad conceptual: no hay una única transacción global; cada microservicio maneja su propia transacción local y comunica el resultado a través de eventos o mensajes.
- Consistencia eventual en lugar de fuerte:
- En transacciones ACID tradicionales (fuerte consistencia), cuando la operación termina, todos los datos están actualizados de forma inmediata y consistente.
- En Sagas, cada microservicio actualiza su propia base de datos de manera independiente y comunica el resultado.
- Esto significa que, en un momento dado, los datos pueden estar desincronizados entre servicios.
- La consistencia no es inmediata, sino que se logra eventualmente, cuando todos los pasos y compensaciones se completan.
- Debugging más difícil: rastrear fallos en un flujo distribuido con múltiples servicios y compensaciones es más complejo que en una transacción centralizada.
- Necesidad de idempotencia y retries bien definidos:
- Idempotencia: la capacidad de ejecutar la misma operación varias veces sin duplicar efectos si un evento llega más de una vez.
- Retries: la capacidad de reintentar una operación fallida de manera controlada hasta que tenga éxito o se alcance un límite, garantizando que los errores transitorios no rompan el flujo del sistema.
Problema: Observabilidad
A medida que el sistema crece, aparece uno de los problemas más duros de los microservicios
- El sistema falla, pero no sabés dónde ni por qué.
- Un request puede atravesar: un API Gateway, varios microservicios, múltiples queues y eventos.
- Los logs locales ya no alcanzan.
- La observabilidad es la capacidad de entender qué está pasando dentro del sistema, solo a partir de sus outputs.
Para eso, podemos usar 3 herramientas fundamentales
Logging distribuido
- Logs centralizados
- Cada request tiene un correlation ID, normalmente es un UUID.
- Permite reconstruir el recorrido de una request
Métricas
- Latencia
- Throughput
- Error rate
- Uso de recursos
Tracing distribuido
- Permite seguir una request a través de múltiples servicios
- Cada salto queda registrado como un span dentro de un trace
Esto es fundamental para: identificar cuellos de botella, entender dependencias y debuggear fallas.
Conclusión
Me quedó mucho más largo de lo que pensaba, pero creo que abarqué todo lo que aprendí de microservicios en la práctica.
Si tenés alguna pregunta, no dudes en contactarme a través de mis redes sociales.