Los tres conceptos de fallo que conviene conocer
Bienvenida
Los sistemas distribuidos fallan de manera predecible. Una vez que aprendes los patrones, cada informe de postmortem se convierte en un ejercicio de reconocimiento en lugar de un misterio.
Tres conceptos cubren la mayor parte de lo importante en el análisis de fallos en producción:
Punto único de fallo (SPOF): un componente cuyo fallo derriba un sistema más grande. A menudo oculto: el servidor DNS en el que todos dependen; el certificado contra el cual todo se renueva; el único maestro de base de datos.
Fallo en cascada: el fallo de un componente desencadena el de otro, que a su vez desencadena el de otro. Una base de datos lenta causa timeouts en la capa de API, lo que provoca reintentos, que cargan aún más la base de datos, lo que causa más timeouts. La onda expansiva se propaga.
Radio de impacto: cuánto del sistema se cae cuando una pieza falla. Las decisiones arquitectónicas delimitan o no delimitan el radio. Un SPOF tiene un radio de impacto ilimitado. Un servicio con compartimentación (bulkhead) tiene un radio limitado.
Al finalizar esta lección, usted podrá:
- Identificar SPOFs en una arquitectura mediante inspección
- Reconocer patrones de fallo en cascada: tropel de trueno (thundering herd), tormenta de reintentos, cola de la muerte
- Leer una línea de tiempo real y separar el detonante del defecto latente que el detonante puso de manifiesto
- Redactar acciones sin culpas (blameless) que apunten a los sistemas en lugar de a las personas, cubriendo prevención / detección / recuperación
- Razonar sobre compartimentación (bulkheads) y disyuntores (circuit breakers) como herramientas para delimitar el radio de impacto
Detecta el Punto Único de Fallo
Inspección de arquitectura por capas
Considera una pequeña arquitectura web:
- DNS: api.example.com -> un único servidor de nombres con la IP 203.0.113.10, alojado por un solo proveedor de DNS
- CDN: un único proveedor de CDN delante de api.example.com
- Ingress: dos máquinas de proxy inverso detrás de un equilibrador de carga
- Backend: seis réplicas de la API en dos zonas de disponibilidad (tres por zona)
- Base de datos: un primario + una réplica de solo lectura, en la misma zona de disponibilidad
- Caché: clúster de Redis, tres nodos distribuidos en las mismas dos zonas de disponibilidad
Pregunta: ¿qué componentes son SPOF? Pista: los SPOF no siempre son del tipo evidente de 'una sola máquina'. Un clúster de tres máquinas en una sola zona de disponibilidad es un SPOF para el fallo de esa zona.
Tres patrones clásicos de cascada
Los fallos se propagan a través de las dependencias
Patrón 1: Enjambre de trueno (Thundering herd). Un recurso compartido (caché, bloqueo, base de datos) falla o se reinicia. Todos los clientes que dependían de él reintentan simultáneamente. La avalancha abruma lo que vuelve a estar disponible; los reintentos se acumulan más rápido de lo que la recuperación puede absorberlos; la recuperación nunca se completa.
Patrón 2: Tormenta de reintentos (Retry storm). Un servicio aguas abajo se ralentiza. Los llamadores aguas arriba, en lugar de fallar, reintentan. Los reintentos multiplican la carga original. El servicio lento se ralentiza aún más, lo que desencadena más reintentos. Eventualmente, la carga supera incluso la capacidad de una versión sana del servicio.
Patrón 3: Cola de la muerte. Una cola de procesamiento sin contrapresión recibe elementos más rápido de lo que los procesa. La cola crece sin límite. La memoria se agota; el consumidor se bloquea; se reinicia; encuentra una cola aún más grande; se bloquea de nuevo.
Hilo conductor: una pequeña perturbación inicial desencadena un bucle de retroalimentación positiva. La propia respuesta del sistema amplifica el fallo en lugar de amortiguarlo.
Mecanismos de amortiguación
Reintento exponencial con jitter. Los clientes que reintentan esperan más tiempo en cada intento, con un desplazamiento aleatorio. Esto previene olas de reintento sincronizadas.
Circuit breaker (disyuntor). Un llamador rastrea la tasa de fallos aguas abajo. Al superar un umbral, el llamador deja de llamar durante un período de enfriamiento y hace fallar sus propias solicitudes de inmediato. Previene trabajo desperdiciado y permite la recuperación del servicio aguas abajo.
Bulkhead (compartimento estanco). Aísla recursos por dependencia. Pila de conexiones A para la base de datos, pila de conexiones B separada para la caché. Una base de datos lenta no puede agotar todas las conexiones; las llamadas a la caché continúan.
Descarga de carga (Load shedding). Cuando está sobrecargado, descarta solicitudes en el borde en lugar de aceptarlas y fallar lentamente. Un 429 en 1 ms es mejor que un 500 en 30 segundos.
Retroalimentación de presión (Backpressure). Frena a los productores cuando los consumidores no pueden seguir el ritmo. Las colas se vuelven acotadas; los emisores se bloquean; la fuente original de trabajo siente la fricción.
Diagnosticar una cascada
La capa de API de un equipo colapsa durante una conmutación por fallo de base de datos de rutina. Cronología:
- 14:00:00 — el operador promociona la base de datos de respaldo. Indisponibilidad esperada: ~10 segundos.
- 14:00:08 — la base de datos principal no está disponible. Las solicitudes del nivel de API comienzan a fallar con errores de conexión a la base de datos.
- 14:00:08 — el nivel de API realiza reintentos (configuración predeterminada: 5 reintentos, sin retroceso, separados por 100 ms).
- 14:00:11 — el nodo de respaldo es promovido y comienza a aceptar nuevas conexiones.
- 14:00:11 — el nivel de API abre miles de nuevas conexiones a la base de datos simultáneamente (cada réplica × cada solicitud concurrente × cada reintento).
- 14:00:13 — el pool de conexiones de la nueva base de datos principal se agota; se rechazan las nuevas conexiones.
- 14:00:13-14:05:00 — las réplicas del nivel de API agotan sus pools de conexiones, lanzan excepciones, se caen, se reinician y repiten el ciclo.
- 14:05:00 — el operador detiene manualmente el tráfico del nivel de API; la base de datos se estabiliza.
- 14:10:00 — Se completa la restauración gradual del tráfico. Tiempo total de interrupción: ~10 minutos (frente a los ~10 segundos esperados).
DNS SERVFAIL: Dos defectos que se combinan
Una autopsia de forma real
Lo que sigue es una versión saneada de un incidente real. Se cambiaron los nombres de los proveedores y se anonimizaron las IPs; la forma, la línea de tiempo y las lecciones son reales.
Resumen
El sitio example.com devolvió SERVFAIL desde todos los resolvers DNS públicos durante aproximadamente 3-4 horas. Las otras 46 zonas en el mismo maestro DNS no se vieron afectadas. Causa raíz: dos defectos que se combinan.
1. El proveedor A (un proveedor de DNS secundario) añadió una nueva IP de sincronización interna que no estaba en la lista de permisos allow-axfr-ips del primario.
2. La zona example.com tenía un conflicto de CNAME que violaba la RFC y tenía años de antigüedad (demo.example.com tenía tanto registros CNAME como MX/TXT en la misma etiqueta), lo que provocó que el proveedor A rechazara la zona en un AXFR nuevo.
Línea de tiempo (UTC)
- ~15:00 — El Proveedor A añade la nueva IP de sincronización 198.51.100.42 a su infraestructura
- 15:02 — aparece el primer AXFR-out denied para 198.51.100.42 en los registros del DNS primario (sin alertas para esta señal)
- ~18:00 — se alcanzó la ventana de expiración del SOA; el Proveedor A elimina la zona example.com de la caché
- ~18:30 — se detecta SERVFAIL externamente
- ~19:45 — se identifica la causa raíz
- 20:00 — 198.51.100.42 se añade a allow-axfr-ips; se reinicia el primario
- 20:05 — se envía NOTIFY; se inicia AXFR; la zona sigue en SERVFAIL (conflicto de CNAME)
- 20:07 — check-zone revela 1 error: conflicto de CNAME en demo.example.com
- 20:09 — CNAME reemplazado por registro A; verificación de zona limpia (0 errores)
- 20:10 — Se envió NOTIFY; AXFR se completa; el Proveedor A comienza a servir la zona
- 20:11 — dig @8.8.8.8 example.com A devuelve la IP correcta — RESUELTO
¿Por qué solo example.com?
Las 47 zonas comparten el mismo primario de DNS. El bloqueo de IP de AXFR afectó a todas las zonas. Pero solo example.com tenía el conflicto de CNAME, y solo example.com necesitaba un nuevo AXFR en el momento en que se aplicó la denegación. Otras zonas ya se habían actualizado antes de la denegación o aún no lo necesitaban.
Defecto latente
El conflicto de CNAME en demo.example.com había existido durante años. Funcionaba porque el primario servía la zona desde su base de datos (tolerante con las violaciones de RFC) y el Proveedor A estaba sirviendo desde datos en caché obsoletos de antes de que se introdujera la violación. Cuando el Proveedor A descartó su caché y necesitó datos nuevos, la violación se manifestó.
Disparador
El proveedor A añadió silenciosamente una nueva IP de sincronización. La lista de permitidos del primario no la incluía. Se denegó el AXFR. Tres horas después (caducidad del SOA), el proveedor A eliminó la zona. El defecto latente se manifestó cuando el sistema intentó recuperarse.
Redactar acciones correctivas sin culpas
Sin culpas: Dirigirse a los sistemas, no a las personas
Una acción correctiva sin culpas señala algo que el sistema debería hacer de manera diferente, no algo que una persona debería hacer de manera diferente. "Formar al operador" es culposo. "Añadir una verificación automatizada que detecte esto antes de la implementación" es sin culpas.
Las buenas acciones correctivas sin culpas se agrupan en tres dimensiones:
- Prevención: hacer que lo malo sea más difícil o imposible
- Detección: notarlo antes si ocurre
- Recuperación: limitar el daño cuando ocurre
Cada elemento debe especificar (1) el cambio de sistema concreto, (2) el equipo responsable y (3) la dimensión que atiende.
Compartimentos que se hunden sin hundir el barco
Prestado de la Ingeniería Naval
Los barcos tienen mamparos estancos: paredes verticales que dividen el casco en compartimentos. Un compartimento puede inundarse sin hundir el barco; otro puede fallar sin afectar al resto.
Los sistemas distribuidos prestan la misma palabra y la misma idea.
Patrón de mamparos: aislar recursos por dependencia. Un servicio que llama a tres APIs aguas abajo utiliza tres pools de conexiones separados, tres pools de hilos separados y tres presupuestos de reintentos separados. Una dependencia lenta o fallida no puede consumir los recursos asignados a las otras dos.
Sin mamparos: una dependencia lenta agota el pool de hilos compartido; las llamadas a otras dependencias se bloquean esperando hilos; el servicio completo se vuelve no responsivo.
Con mamparos: una dependencia lenta agota su propio pool; las llamadas a ella fallan rápidamente; las llamadas a otras dependencias continúan normalmente; el radio de impacto se mantiene acotado a la dependencia fallida.
Disyuntores
Patrón de disyuntor (circuit breaker): un envoltorio con estado alrededor de una dependencia de nivel inferior que rastrea la tasa de fallos. Tres estados:
- Cerrado (normal): las llamadas pasan a través. Se cuentan los fallos.
- Abierto (disparado): al superar un umbral de fallos (por ejemplo, 50% de fallos en los últimos 30 segundos), el disyuntor se abre. Las llamadas fallan inmediatamente sin intentar contactar la dependencia. Esto ahorra trabajo al llamador y protege a la dependencia de recibir carga mientras está en un estado no saludable.
- Semiabierto (prueba): tras un período de enfriamiento, el disyuntor deja pasar una pequeña fracción de llamadas. Si tienen éxito, vuelve a cerrarse a la normalidad. Si fallan, se reabre para otro período de enfriamiento.
La clave: el disyuntor evita el esfuerzo desperdiciado durante períodos de salud conocida deficiente y le da a la dependencia de nivel inferior la oportunidad de recuperarse sin carga continua.
Los muros cortafuegos (bulkheads) limitan el radio de impacto. Los disjuntores (circuit breakers) impiden que el impacto se mantenga a sí mismo.
Limitar el radio de impacto
Tu servicio de API llama a cuatro servicios de nivel inferior: Servicio de Usuario, Servicio de Recomendaciones, Servicio de Notificaciones y una API de Pagos de terceros. El equipo ha oído que 'el Servicio de Recomendaciones ha estado un poco inestable' y quiere asegurarse de que, cuando falle, el resto del sistema permanezca saludable.
Hoy, el servicio utiliza un solo conjunto de hilos compartido de 200 hilos y un solo conjunto de conexiones HTTP compartido. Los cuatro servicios downstream compiten por estos recursos. No hay circuit breakers.
Diseñar una Revisión de Modos de Fallo
Síntesis
Has aprendido a identificar puntos únicos de fallo (SPOF) mediante inspección, reconocer patrones de fallo en cascada, separar el detonante del defecto latente al leer un análisis post-mortem, redactar elementos de acción sin culpas en las áreas de prevención / detección / recuperación, y limitar el radio de impacto mediante mamparos (bulkheads) + disyuntores (circuit breakers) + degradación elegante.
Aplica los cinco.
Tu equipo está lanzando un nuevo servicio search.example.com que depende de tres servicios aguas abajo: un índice de búsqueda principal (index.example.com), un servicio de analítica (analytics.example.com) y un servicio de recomendaciones (recs.example.com). El equipo quiere que dirijas una "revisión de modos de fallo" antes del lanzamiento.
Hacia dónde va este curso
Hacia dónde va este curso
Ahora puedes identificar un SPOF, reconocer una cascada, leer un postmortem de manera productiva, redactar elementos de acción sin culpas y limitar el radio de impacto por diseño.
La lección final de este curso (cs_distsys_observability_and_capacity) enseña qué medir para que descubras que un problema está ocurriendo antes de que lo hagan los usuarios. Verificaciones de salud, puntos de acceso de versión, las cuatro señales doradas en una capa de proxy y cómo las decisiones de capacidad de pico se vinculan con los datos observados.
Lección complementaria: geometry_of_failure_modes_and_blast_radius deriva la centralidad de intermediación (qué nodo del grafo es el cuello de botella) y el corte mínimo (el límite del radio de impacto).
Buen trabajo. Adelante.