Tema 13

13. Comunicación síncrona y asíncrona: resiliencia, timeouts y circuit breakers

En microservicios, la forma en que los componentes se comunican define buena parte de su estabilidad y también de su seguridad operacional. Una llamada mal diseñada, un retry sin límites o una dependencia demasiado frágil pueden convertir una falla local en una degradación sistémica.

Objetivo Diseñar interacciones más resistentes a fallos
Enfoque Dependencias, degradación y contención
Resultado Evitar cascadas de error y abuso accidental

13.1 Introducción

En un sistema distribuido cada llamada entre componentes es una posible fuente de latencia, error o saturación. A diferencia de una llamada interna en memoria, una interacción remota depende de la red, del estado del servicio remoto, de colas intermedias, de timeouts y de múltiples factores que pueden degradarse parcialmente.

Por eso la comunicación entre servicios no es solo un problema funcional. También es un problema de disponibilidad, contención de fallos y seguridad operacional. Un diseño ingenuo puede hacer que una dependencia lenta o abusada arrastre a todo el sistema.

En este tema analizaremos los tradeoffs entre comunicación síncrona y asíncrona, y veremos mecanismos como timeouts, retries controlados, circuit breakers y backpressure para reducir el impacto de fallos y comportamientos anómalos.

13.2 Comunicación síncrona

La comunicación síncrona ocurre cuando un componente realiza una llamada y espera una respuesta para continuar. Es común en APIs REST, gRPC o invocaciones RPC internas. Su ventaja principal es la simplicidad conceptual: el flujo es directo y la respuesta suele llegar en el mismo contexto de ejecución.

Pero esa simplicidad trae dependencia temporal. Si el servicio remoto tarda, falla o responde de manera intermitente, el componente llamador queda afectado inmediatamente.

13.3 Comunicación asíncrona

La comunicación asíncrona desacopla temporalmente a emisor y receptor. El emisor publica un mensaje o evento y continúa sin esperar que el consumidor termine en ese mismo instante. Esto mejora desacople y tolerancia a ciertos picos o retrasos, pero introduce complejidad adicional en consistencia, observabilidad y manejo de errores.

La asincronía no elimina el problema de fallos; solo cambia su forma. Los errores pueden aparecer como retrasos, duplicaciones, reintentos, desorden de mensajes o acumulación en colas.

13.4 Cuándo conviene cada estilo

Estilo Ventaja principal Riesgo principal
Síncrono Flujo directo y respuesta inmediata Acoplamiento temporal y cascadas de latencia
Asíncrono Desacople y amortiguación temporal Mayor complejidad de consistencia y trazabilidad

No existe un estilo universalmente mejor. La elección depende de la necesidad funcional, la criticidad del flujo, la tolerancia al retraso y el costo de la inconsistencia temporal.

13.5 Fallos parciales y cascadas

Uno de los rasgos más difíciles de los sistemas distribuidos es el fallo parcial. Un componente puede estar disponible para algunas solicitudes y no para otras, responder lentamente, rechazar parte del tráfico o degradarse sin caerse por completo. Esa ambigüedad hace más difícil decidir qué hacer desde el cliente.

Si varios servicios dependen en cadena entre sí, una degradación parcial puede propagarse. Un timeout en un servicio puede disparar retries, aumentar carga en el siguiente y generar una cascada que termine afectando todo el sistema.

En microservicios, la indisponibilidad no siempre se presenta como caída total. Muchas veces aparece como lentitud, saturación o respuestas intermitentes que erosionan el sistema entero.

13.6 Timeouts

Un timeout es el límite de tiempo tras el cual el llamador deja de esperar una respuesta. Parece un detalle técnico menor, pero en realidad es una decisión de arquitectura. Sin timeouts adecuados, los threads, conexiones o recursos del cliente pueden quedar bloqueados demasiado tiempo y amplificar una degradación remota.

Diseñar timeouts exige equilibrio:

  • Un timeout demasiado largo consume recursos y amplifica latencia.
  • Un timeout demasiado corto genera fallos artificiales y reintentos innecesarios.
  • Distintos flujos pueden requerir distintos presupuestos de tiempo.

13.7 Retries y riesgo de amplificación

Los retries ayudan a recuperarse de fallos transitorios, pero también pueden empeorar drásticamente una degradación. Si muchos clientes reintentan sin coordinación cuando un servicio ya está saturado, la carga aumenta justo cuando menos capacidad hay para absorberla.

Por eso los retries deberían ser:

  • Limitados en cantidad.
  • Aplicados solo sobre operaciones apropiadas.
  • Espaciados con estrategias de backoff.
  • Observados para detectar tormentas de reintentos.

13.8 Idempotencia y repetición segura

Si una operación puede repetirse por retries o duplicación de mensajes, conviene preguntarse si es idempotente. Una operación idempotente permite múltiples intentos con el mismo efecto final esperado. Sin esta propiedad, los reintentos pueden generar cobros duplicados, actualizaciones inconsistentes o efectos irreversibles.

La idempotencia es una pieza clave de resiliencia y también una barrera frente a abuso accidental o malicioso de repeticiones.

13.9 Circuit breakers

El circuit breaker corta temporalmente el flujo hacia una dependencia que está fallando o degradada. En lugar de seguir enviando solicitudes que probablemente fallen, el sistema rechaza temprano o desvía a una estrategia degradada hasta que la dependencia pueda evaluarse nuevamente.

Su valor principal es evitar que el cliente desperdicie recursos y evitar que la dependencia colapsada siga recibiendo presión innecesaria.

Estado Qué ocurre Objetivo
Cerrado El tráfico circula normalmente Operación estándar
Abierto Se bloquean llamadas hacia la dependencia Contener degradación
Half-open Se prueba gradualmente si la dependencia se recuperó Recuperación controlada

13.10 Backpressure y control de carga

Cuando un componente no puede procesar más trabajo al ritmo de llegada, necesita alguna forma de backpressure: señal o mecanismo que reduzca, rechace o regule la presión entrante. Sin esto, la cola interna crece, la latencia se dispara y la falla se propaga.

El backpressure puede expresarse en:

  • Límites de concurrencia.
  • Rechazo temprano de solicitudes.
  • Colas con capacidad acotada.
  • Priorización de tráfico crítico.

13.11 Degradación elegante

No todos los fallos requieren caída total. En muchos casos conviene diseñar degradación controlada: deshabilitar funciones no críticas, servir información cacheada, responder con un estado limitado o retrasar procesamiento no urgente.

Esta estrategia mejora continuidad operativa y también reduce el impacto de ataques de saturación o comportamientos anómalos temporales.

13.12 Resiliencia y seguridad operacional

Aunque estos mecanismos suelen presentarse como temas de disponibilidad, también influyen en seguridad. Un sistema sin límites claros de tiempo y carga es más vulnerable a abuso, a denegaciones parciales y a efectos secundarios de componentes comprometidos o defectuosos.

Retries descontrolados, colas infinitas o timeouts mal elegidos pueden convertir un problema técnico menor en un incidente operativo serio.

13.13 Observabilidad de dependencias

No alcanza con implementar circuit breakers y timeouts. También hay que observarlos. Para eso conviene medir:

  • Latencia por dependencia.
  • Tasa de errores y tipos de fallo.
  • Volumen de retries.
  • Aperturas y cierres de circuit breakers.
  • Profundidad de colas y tiempos de espera.

Sin esta visibilidad, la resiliencia queda configurada pero no gobernada.

13.14 Errores comunes

  • Encadenar demasiadas llamadas síncronas en un mismo flujo crítico.
  • Configurar retries automáticos sin límites ni backoff.
  • Omitir timeouts o dejar valores por defecto no revisados.
  • Usar colas como solución mágica sin plan para duplicación o retraso.
  • No diseñar respuestas degradadas para funciones no esenciales.
La resiliencia no aparece por agregar librerías. Aparece cuando el diseño asume que las dependencias fallan y define qué hacer antes de que eso ocurra.

13.15 Qué debes recordar de este tema

  • La comunicación entre servicios define parte central de la estabilidad del sistema.
  • Síncrono y asíncrono tienen ventajas y riesgos distintos; ninguno elimina por sí solo los fallos.
  • Timeouts, retries e idempotencia deben diseñarse en conjunto.
  • Circuit breakers y backpressure ayudan a contener degradaciones y cascadas.
  • La resiliencia también es una defensa frente a abuso y denegación parcial del servicio.

13.16 Conclusión

Una arquitectura distribuida segura no solo protege identidad y acceso. También protege la capacidad del sistema para seguir operando cuando algo falla, se degrada o es abusado. Diseñar comunicación con límites claros, degradación controlada y observabilidad suficiente permite transformar fallos inevitables en incidentes contenidos en lugar de crisis sistémicas.

En el próximo tema estudiaremos seguridad en colas, eventos y arquitecturas basadas en mensajería para profundizar cómo proteger la comunicación asíncrona y sus riesgos particulares.