Cascading Failures

Qué es

Cascading Failure es la propagación de degradación o fallo desde un componente hacia otros mediante dependencias, recursos compartidos o mecanismos de recuperación que trasladan presión. Una falla inicialmente acotada cambia las condiciones de funcionamiento de sus vecinos; estos pierden capacidad y afectan a otros. La característica central es la relación causal de propagación, no el número de alertas.

Varios fallos independientes no constituyen por sí solos una cascada. Dos servicios pueden fallar simultáneamente por una interrupción común de infraestructura. Eso muestra correlación o una causa compartida; para identificar una cascada hay que explicar cómo la degradación de una parte provoca o amplifica la de otra.

Service A degraded
    -> Service B waits longer
    -> threads / connections / pending work accumulate
    -> Service B loses useful capacity
    -> Service C receives shifted load or slower responses
    -> degradation propagates

Dependencias y recursos retenidos

El acoplamiento síncrono transmite latencia: una solicitud espera una respuesta antes de avanzar y retiene algún recurso durante esa espera. Puede ser un thread, conexión, permiso, objeto en memoria o slot de concurrencia. Un runtime asíncrono reduce ciertas esperas bloqueantes, pero no convierte esos recursos ni el trabajo pendiente en ilimitados.

Cuando la dependencia tarda más, aumenta la ocupación necesaria para sostener el mismo ritmo. El pool puede agotarse; solicitudes nuevas esperan y consumen presupuesto de deadline. Si la cola crece, crecen también memoria y edad. Un servicio que estaba sano puede entrar en overload sin que aumente la demanda original.

Google SRE analiza esta interacción entre solicitudes en vuelo, recursos agotados y síntomas secundarios que parecen causas iniciales. El fallo visible puede estar varios saltos después del componente que cambió primero. Addressing Cascading Failures.

La cola tampoco rompe automáticamente el acoplamiento. Puede desacoplar la respuesta inmediata del cliente y conservar intención, pero un backlog sostenido ocupa almacenamiento y retrasa efectos de negocio. queue-management exige revisar límites y vigencia, incluso cuando el transporte es durable.

Recuperación que amplifica

timeout puede acotar retención local, aunque no garantice cancelar la ejecución remota. Un valor excesivamente largo acumula esperas; uno demasiado corto puede clasificar respuestas atendibles como fallidas y activar nuevas tentativas. La propagación depende de la combinación de duración, límites y reacción del caller.

retry agrega trabajo cuando la política lo permite. Si la causa es capacidad insuficiente, insistir puede mantenerla. retry-storms describe el feedback en que esa repetición sostiene o agrava la degradación. Si las políticas de varias capas son independientes, una intención puede multiplicarse antes de llegar al recurso agotado.

Failover también puede trasladar presión sin duplicar cada solicitud. Desviar tráfico desde un destino degradado hacia otro reduce carga allí y la aumenta en el receptor. Si el destino alternativo no tiene margen, la recuperación de una parte inicia otro fallo. Dos endpoints distintos pueden compartir base de datos o red, de modo que cambiar de endpoint no garantiza independencia.

Un fallback costoso puede repetir ese problema: una alternativa válida para un fallo individual no necesariamente puede atender todo el tráfico durante un incidente. La capacidad de las rutas de error y recuperación importa tanto como la del camino normal. AWS documenta cómo una alternativa a una cache fallida trasladó presión a una DB compartida y extendió la interrupción. Avoiding fallback in distributed systems.

Infraestructura compartida y correlación

Un servicio de logging, pool global, base de datos, autenticación o router compartido puede cruzar límites que parecían aislados. Si cada error genera una escritura de diagnóstico costosa, más errores consumen más recurso común; otros servicios pueden perder capacidad por un camino ajeno al grafo de llamadas principal.

Conviene distinguir causa común de propagación posterior. La pérdida de un nodo puede afectar simultáneamente dos servicios y luego sus retries saturar un tercero. El incidente contiene ambos fenómenos. Tampoco correlacionar timestamps demuestra dirección causal: una solicitud lenta puede reflejar una dependencia anterior o ser consecuencia de una cola local.

blast-radius expresa cuánto impacto alcanza la dinámica. Una cascada puede quedar contenida en un tenant o atravesar regiones según las dependencias y reservas compartidas. Contar servicios afectados no describe por sí solo usuarios, datos o funciones comprometidas.

Ejemplo: el API como síntoma

Supongamos API → Order → Payment → Database. Database se vuelve lento sin dejar de responder. Payment retiene conexiones hasta agotarlas; Order acumula llamadas y su pool compartido termina ocupado. El API comienza a expirar solicitudes y parece ser el componente que falló.

La degradación de Database es el disparador ilustrativo, pero no explica por sí sola la extensión del impacto. El pool compartido, las esperas y los retries determinan cómo alcanza operaciones que no necesitaban Payment. Si Order comparte workers con consultas de inventario, estas también pueden quedar indisponibles aunque su backend esté sano.

El componente que finalmente falla no es necesariamente la causa original. Tampoco basta con atribuir todo a Database: corregir su lentitud puede no vaciar las colas ni detener los intentos pendientes. Este análisis describe dinámica; no reemplaza un proceso completo de investigación de incidentes.

Contención y límites de las mitigaciones

bulkhead puede reservar capacidad para otros grupos, pero no aísla automáticamente disco, memoria o una DB común. circuit-breaker puede reducir llamadas hacia una dependencia no saludable, pero una clasificación equivocada amplía indisponibilidad o concentra probes durante recuperación.

load-shedding puede ahorrar trabajo antes de agotar recursos. Si llega tarde, consume capacidad antes de rechazar; si borra obligaciones durables, cambia el fallo de disponibilidad por pérdida de intención. admission-control necesita hacer cumplir la reserva en la frontera relevante, y backpressure necesita participantes que realmente desaceleren.

Estos mecanismos reducen ciertos caminos de propagación; ninguno garantiza eliminar cascadas. Su orden, scope y observaciones deben ser deliberados. Rechazar nuevas compras puede proteger consultas, pero no convierte compras rechazadas en operaciones exitosas.

Prevención, diagnóstico y recuperación

Reconstruir por etapa llegadas originales y adicionales, latencia de espera, ejecución, ocupación, rechazos y goodput. Revisar infraestructura común y cambios de enrutamiento. Mantener capacidad para completar trabajo, coordinar recuperación y observar sin que todo el diagnóstico dependa del recurso agotado.

La recuperación necesita restablecer la dependencia y reducir la presión que la rodea: limitar nuevos compromisos, drenar backlog válido y espaciar reintroducción. Abrir todos los límites al primer éxito puede producir thundering-herd. Si el trigger desaparece y el feedback mantiene el fallo, revisar metastable-failures.

Usar este concepto cuando exista evidencia de transferencia causal de degradación. No usarlo como sinónimo de cualquier incidente grande ni asumir una única cadena lineal: varios caminos y loops pueden coexistir. failure-dynamics permite recorrer propagación, amplificación, sincronización y alcance como preguntas distintas.