Marcio Cunha

¿Microservicios inestables? Cómo usar circuit breaker y fallbacks

Aprende a proteger tu arquitectura distribuida contra fallas en cascada usando el patrón circuit breaker y respuestas de fallback bajo alta carga.

Marcio Cunha•4 min
También disponible en:EnglishPortuguês
Resumen
  • El patrón circuit breaker detiene llamadas a servicios inestables para proteger el ecosistema de fallas en cascada.
  • Las respuestas de fallback garantizan que el sistema siga operativo incluso cuando dependencias críticas caen.
  • Monitorear tasas de error y latencia permite ajustar la sensibilidad del disyuntor según el tráfico real.
  • Estrategias consistentes de transacciones distribuidas evitan estados inconsistentes ante fallas de red, como en consistencia transaccional con Saga .
  • Probar fallas simuladas en entornos controlados asegura que los mecanismos de recuperación respondan bien bajo presión.

¿Por qué los microservicios fallan juntos bajo alta carga?

Cuando dividimos un sistema grande en bloques más pequeños llamados microservicios, ganamos libertad para escalar partes aisladas. Sin embargo, creamos una red compleja de dependencias donde una sola falla puede propagarse rápidamente. Si el servicio de pagos se congela por lentitud en la base de datos, las peticiones comienzan a acumularse en colas de espera. En la práctica, esto significa que los hilos y conexiones de red se agotan en cadena, derribando toda la aplicación debido a un cuello de botella localizado.

En las arquitecturas modernas, el mayor peligro no es solo que falle un servicio, sino cómo los sistemas clientes reaccionan a esa indisponibilidad. Sin mecanismos de protección, cada nuevo intento de petición consume valiosos recursos de CPU y memoria esperando una respuesta que nunca llega. La ingeniería de software aplica patrones defensivos precisamente para resolver este problema de agotamiento de recursos.

¿Qué es un circuit breaker y cómo funciona?

Inspirado en los disyuntores eléctricos de nuestros hogares que cortan la energía ante sobrecargas, el circuit breaker es un componente de software que monitorea llamadas entre servicios. Opera básicamente en tres estados: cerrado, abierto y semiabierto. En el estado cerrado, las peticiones fluyen con normalidad hacia el servicio externo. Cuando los errores superan un límite tolerable, el disyuntor se abre, bloqueando de inmediato nuevos intentos y evitando desperdiciar tiempo y recursos.

Mientras el circuito permanece abierto, cualquier llamada al servicio defectuoso falla al instante, devolviendo una respuesta alternativa programada. Tras un periodo determinado, el disyuntor pasa a un estado semiabierto, permitiendo que una sola petición pruebe el terreno. Si tiene éxito, el circuito se cierra de nuevo; si falla, vuelve al estado abierto. Esta dinámica protege tanto al cliente como al servidor sobrecarregado, dando tiempo al sistema para recuperarse.

Implementando fallbacks inteligentes para mantener vivo el sistema

Bloquear una petición con el circuit breaker resuelve el agotamiento de recursos, pero deja al usuario sin respuesta si no hay un plan alternativo. Aquí es donde entran los fallbacks, que actúan como un plan B operativo cuando la herramienta principal falla. En lugar de mostrar un error genérico o romper la página entera, el sistema entrega datos en caché, información parcial o un mensaje amigable informando sobre inestabilidad temporal.

Para asegurar que este flujo funcione sin corromper datos transaccionales complejos, muchos equipos combinan disyuntores con enfoques de resiliencia, alineándose con estrategias robustas como la gestión de consistencia transaccional en microservicios. El secreto de un buen fallback es equilibrar utilidad y sencillez, garantizando que la ruta alternativa sea rápida, ligera y ajena al componente que acaba de fallar.

Ejemplo práctico de circuit breaker en código

Para entender cómo funciona esto en la práctica, podemos observar una implementación básica usando bibliotecas modernas de resiliencia en lenguajes de backend. El código siguiente muestra cómo configurar un disyuntor que monitorea fallas y activa una respuesta de fallback automática si el servicio externo tarda demasiado o devuelve errores consecutivos.

const { CircuitBreaker } = require('opossum');

async function llamarServicioPago(datos) {
  // Simula una llamada a API externa que puede fallar
  if (Math.random() > 0.5) throw new Error('Servicio no disponible');
  return 'Pago aprobado';
}

const options = {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 10000
};

const breaker = new CircuitBreaker(llamarServicioPago, options);

breaker.fallback(() => 'Sistema inestable. Intente más tarde.');

breaker.fire({ id: 123 })
  .then(console.log)
  .catch(console.error);

En el ejemplo anterior, configuramos un tiempo límite de tres segundos y establecimos que si el cincuenta por ciento de las peticiones fallan, el disyuntor se abre durante diez segundos. Durante ese intervalo, la función de fallback toma el control de inmediato. Esto evita que picos de lentitud externa paralicen todo el microservicio principal, preservando la experiencia general del usuario. Para complementar esta implementación en entornos de producción, consulte también nuestros análisis técnicos sobre ¿Ruido electromagnético en la placa? Cómo eliminar EMI enrutando y Servidor lento? Cómo hallar cuellos de botella de disco e IOPS.

Consideraciones finales sobre resiliencia distribuida

Desarrollar aplicaciones resilientes exige un cambio de mentalidad donde asumimos que las fallas de red y las caídas de servidores son eventos normales, no excepciones improbables. El uso combinado de circuit breakers y fallbacks transforma sistemas frágiles en estructuras capaces de absorber impactos sin colapsar. Al planificar tu arquitectura, recuerda que la estabilidad de un sistema distribuido depende tanto de la solidez de los servicios principales como de la inteligencia con la que gestiona la indisponibilidad ajena.