El problema de las fallas en cascada
En sistemas de pago distribuidos, un servicio lento puede tumbar toda la cadena. Lo aprendimos por experiencia directa trabajando en infraestructura de procesamiento de pagos en el sector bancario. Una sola degradación en un servicio downstream — tal vez un motor de detección de fraude corriendo lento, tal vez un core bancario bajo carga inusual — se propagaba por todo el pipeline de pagos, convirtiendo un retraso menor en una caída total del sistema.
El patrón es predecible. El Servicio A llama al Servicio B. El Servicio B está lento, así que el pool de hilos del Servicio A se llena con requests esperando. El Servicio A deja de responder a nuevos requests. Ahora el Servicio C, que depende del Servicio A, comienza a tener timeouts. En minutos, un problema que comenzó en un componente se ha propagado a cada servicio en la cadena.
En procesamiento de pagos, esto no es solo un problema de ingeniería. Cada minuto de downtime significa que las transacciones no se están procesando. Para un banco grande, eso se traduce en impacto financiero real medido en miles de dólares por minuto.
Por qué los timeouts estándar no son suficientes
El primer instinto al lidiar con servicios downstream lentos es agregar timeouts. Configura un timeout de 5 segundos en cada llamada externa, y si no responde a tiempo, falla rápido y devuelve un error. Esto ayuda, pero no resuelve el problema fundamental.
Solo con timeouts, cada request todavía tiene que esperar el período completo de timeout antes de fallar. Si un servicio downstream está completamente caído, le sigues enviando requests — requests que siempre van a fallar, pero solo después de esperar 5 segundos cada uno. Bajo alta carga, esto significa que tu pool de hilos sigue siendo consumido por requests condenados al fracaso.
Lo que necesitas es un mecanismo que detecte cuándo un servicio downstream está fallando y deje de enviarle requests por completo. Ese es el patrón circuit breaker.
El patrón circuit breaker
El concepto viene de la ingeniería eléctrica. Un circuit breaker tiene tres estados:
Cerrado (operación normal). Los requests fluyen normalmente. El circuit breaker monitorea las tasas de fallo. Si los fallos exceden un umbral configurado — digamos, 50% de los requests fallando dentro de una ventana de 30 segundos — el circuit breaker se activa.
Abierto (protegiendo el sistema). No se envían requests al servicio downstream. En su lugar, el circuit breaker devuelve inmediatamente una respuesta de fallback o un error. Esto previene la cascada. El circuit breaker permanece abierto por una duración configurada — típicamente usamos 30 a 60 segundos.
Semi-abierto (probando la recuperación). Después de que el período abierto expira, el circuit breaker permite un número limitado de requests de prueba. Si esos requests tienen éxito, el circuit breaker se cierra y la operación normal se reanuda. Si fallan, el circuit breaker se abre de nuevo.
Implementación en nuestro contexto bancario
En nuestro trabajo con IBM Sterling e IBM MQ para procesamiento de pagos, implementamos circuit breakers en varios puntos de integración críticos. La arquitectura involucraba múltiples servicios comunicándose a través de colas de mensajes y llamadas API síncronas.
Las decisiones clave en nuestra implementación fueron:
Umbrales de fallo por servicio. No todos los servicios merecen el mismo umbral. Para el core bancario — que es el más crítico y el más propenso a experimentar problemas de carga — configuramos un umbral más bajo. Cinco fallos consecutivos activaban el circuit. Para servicios menos críticos, permitimos una tasa de fallo mayor antes de activar.
Estrategias de fallback. Aquí es donde ocurre la ingeniería real. Cuando un circuito se abre, necesitas decidir qué pasa con el request. Para procesamiento de pagos, definimos tres estrategias dependiendo del servicio:
Para servicios de enriquecimiento no críticos (como agregar el nombre del beneficiario a una transferencia), el fallback era proceder sin el enriquecimiento y agregarlo asincrónicamente después.
Para servicios de validación críticos (como detección de fraude), el fallback era encolar la transacción para revisión manual en lugar de bloquearla completamente o aprobarla sin validación.
Para servicios del core bancario, el fallback era encolar la transacción con entrega garantizada y procesarla cuando el servicio se recuperara. Esto requirió atención cuidadosa a la idempotencia — cada transacción necesitaba ser reintentable de forma segura.
Monitoreo del estado del circuito. Un circuit breaker solo es útil si sabes cuándo se activa. Construimos monitoreo que rastreaba cambios de estado del circuito en tiempo real. Cuando un circuito se abría, se disparaba una alerta inmediatamente. El dashboard mostraba qué circuitos estaban abiertos, cuánto tiempo llevaban abiertos y la tasa de fallo que los activó.
Los resultados
Después de implementar circuit breakers en todo el pipeline de procesamiento de pagos, medimos lo siguiente durante un período de seis meses:
70% de reducción en incidentes críticos. Antes de los circuit breakers, una sola degradación de servicio causaba fallas en cascada que afectaban todo el sistema. Después de la implementación, las fallas se contenían al servicio afectado.
Estabilidad en tiempos de respuesta. Los tiempos de respuesta promedio durante problemas de servicios downstream bajaron de minutos (cuando todo el sistema estaba degradándose) a milisegundos (circuit breaker devolviendo fallback inmediatamente).
Recuperación más rápida. Porque el circuit breaker deja de enviar tráfico a un servicio que está fallando, ese servicio se recupera más rápido. Ya no está siendo abrumado por requests que no puede manejar.
La perspectiva contraintuitiva es que al fallar más rápido, fallas menos. Al negarte a enviar requests a un servicio que no puede manejarlos, proteges tanto tu sistema como el servicio downstream.
Observabilidad del estado de los circuitos
Los circuit breakers generan una nueva categoría de datos operacionales que tu monitoreo necesita capturar. Rastreamos:
Transiciones de estado del circuito. Cada vez que un circuito se abre, semi-abre o cierra, lo registramos con el timestamp, la tasa de fallo que causó la transición y el servicio afectado.
Tasas de activación de fallback. Con qué frecuencia se usa cada estrategia de fallback. Si un fallback se activa frecuentemente, significa que el servicio subyacente tiene un problema de confiabilidad que necesita atención.
Tiempo de recuperación. Cuánto tiempo permanecen abiertos los circuitos antes de cerrarse exitosamente de nuevo. Esta métrica te dice cuánto tardan tus servicios downstream en recuperarse de problemas.
Distribución de requests. Durante el estado semi-abierto, cuántos requests de prueba tienen éxito versus fallan. Esto muestra si el servicio downstream realmente se está recuperando o solo está fluctuando.
Lecciones aprendidas
Los circuit breakers no son una bala de plata. Son un patrón que funciona cuando se implementa con atención a las características específicas de tu sistema. Las lecciones más importantes de nuestra implementación:
Diseña tus fallbacks primero. El circuit breaker en sí es simple. Lo difícil es decidir qué pasa cuando se activa. Si no tienes una buena estrategia de fallback, un circuit breaker solo convierte un fallo lento en un fallo rápido — lo cual es mejor, pero no suficiente.
Prueba el comportamiento del circuit breaker bajo carga. Descubrimos edge cases en nuestra implementación que solo aparecían bajo carga de nivel producción. El circuit breaker mismo necesita ser resiliente — no puede convertirse en un cuello de botella.
Ajusta los umbrales basándote en datos reales. No adivines los umbrales de fallo. Ejecuta el sistema, observa los patrones reales de fallo y ajusta en consecuencia. Umbrales demasiado sensibles causan activaciones innecesarias del circuito. Umbrales demasiado indulgentes permiten cascadas.
Los circuit breakers son un patrón dentro de una estrategia de resiliencia más amplia. Combinados con configuración adecuada de timeouts, políticas de reintento con backoff exponencial y aislamiento de tipo bulkhead, forman la base de un sistema de pagos que degrada graciosamente en lugar de fallar catastróficamente.