Chaos Engineering
Construye sistemas resilientes inyectando fallos intencionadamente y observando cómo responden y se recuperan tus servicios distribuidos.
Visión General
Chaos engineering significa romper tu propio sistema a propósito — matar un pod, añadir 500ms de latencia, descartar paquetes — y ver si degrada con gracia o se lleva a todos por delante. Netflix lo hizo primero con Chaos Monkey, que termina instancias de producción al azar cada día laboral. Lo importante no es romper: es lo que te cuentan los dashboards después. Litmus, Gremlin y AWS Fault Injection Simulator ya empaquetan la misma idea para que no tengas que escribir tus propios kill scripts.
Esta página es la compañera práctica de la Guía de Chaos Engineering: configs reales de inyección de fallos, un verificador de steady state y un runbook de game day que puedes copiar.
Cuándo Usarlo
Recurre a experimentos de chaos cuando:
- Tu sistema es suficientemente distribuido como para que la caída de una dependencia no debería tumbarlo — pero no estás seguro de que no lo hará. (Microservicios Event-Driven cubre el lado resiliente de esa arquitectura.)
- Hay un drill de disaster recovery o un game day en el calendario y necesitas experimentos concretos, no solo una reunión. (Load Testing cubre la mitad de capacidad del drill.)
- Has construido auto-scaling, failover o auto-curación y nunca lo has visto funcionar de verdad. Los health checks por sí solos no prueban la recuperación — Health Check Endpoint deja los probes bien primero.
- Se acerca un lanzamiento o un evento de alto tráfico y “debería ir bien” no es un plan. Retry Logic es la otra mitad de la degradación elegante.
Cómo Funciona un Experimento
Todo experimento sigue el mismo bucle sea cual sea la herramienta: mide el comportamiento normal, plantea una hipótesis falsable (“si muere la base de datos primaria, el failover se completa en menos de 30 segundos”), inyecta un fallo con el menor radio de impacto que aún responda la pregunta, y o bien confirma la hipótesis o aborta, arregla y repite.
Solución
Pod Chaos en Kubernetes (Litmus)
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
name: pod-delete-experiment
spec:
appinfo:
appns: 'production'
applabel: 'app=payment-service'
appkind: 'deployment'
chaosServiceAccount: litmus-admin
experiments:
- name: pod-delete
spec:
components:
env:
- name: TOTAL_CHAOS_DURATION
value: '30'
- name: CHAOS_INTERVAL
value: '10'
- name: FORCE
value: 'false'
Inyección de Latencia de Red (tc + Bash)
#!/bin/bash
# Añade 500ms de latencia al tráfico de salida en eth0
echo "Inyectando 500ms de latencia durante 60 segundos..."
tc qdisc add dev eth0 root netem delay 500ms 50ms distribution normal
sleep 60
echo "Eliminando latencia..."
tc qdisc del dev eth0 root
# Verificar con ping
ping -c 5 api.example.com
AWS Fault Injection Simulator (Python)
import boto3
fis = boto3.client('fis')
response = fis.start_experiment(
experimentTemplateId='EXT-12345678',
tags={'Environment': 'staging'}
)
print(f"Experiment started: {response['experiment']['id']}")
Ataque Gremlin (Estrés de CPU)
# Instalar Gremlin CLI
sudo apt-get install gremlin
# Estrés de CPU en un contenedor concreto durante 60 segundos
gremlin attack cpu --percent 80 --length 60 --container <container-id>
# Blackhole de red (descarta todo el tráfico a una dependencia)
gremlin attack blackhole --ip 10.0.4.20 --length 30
# Consumo de memoria
gremlin attack memory --percent 75 --length 45
Toxiproxy (Caos de Red para Dependencias)
# Arrancar Toxiproxy
docker run -p 8474:8474 -p 3306:3306 ghcr.io/shopify/toxiproxy:latest
# Crear un proxy para MySQL
toxiproxy-cli create mysql-proxy -l 0.0.0.0:3306 -u 127.0.0.1:3307
# Añadir 2000ms de latencia a las conexiones MySQL
toxiproxy-cli toxic add mysql-proxy -n latency -t latency=2000
# Añadir timeout (las conexiones caen tras 500ms)
toxiproxy-cli toxic add mysql-proxy -n timeout -t timeout=500
# Eliminar todos los toxics
toxiproxy-cli toxic delete mysql-proxy -n latency
Script de Verificación de Steady State
import requests
import time
import sys
def check_steady_state():
"""Verifica los SLOs antes, durante y después de los experimentos de chaos."""
checks = [
("https://api.example.com/health", 200, 500), # URL, status_esperado, latencia_máx_ms
("https://api.example.com/metrics", 200, 1000),
]
all_pass = True
for url, expected_status, max_latency in checks:
try:
start = time.time()
resp = requests.get(url, timeout=5)
latency_ms = (time.time() - start) * 1000
if resp.status_code != expected_status:
print(f"FAIL: {url} returned {resp.status_code}, expected {expected_status}")
all_pass = False
elif latency_ms > max_latency:
print(f"FAIL: {url} latency {latency_ms:.0f}ms exceeds {max_latency}ms")
all_pass = False
else:
print(f"OK: {url} - {resp.status_code} in {latency_ms:.0f}ms")
except requests.RequestException as e:
print(f"FAIL: {url} unreachable: {e}")
all_pass = False
return all_pass
if __name__ == "__main__":
if not check_steady_state():
print("Steady state violado. Abortando experimento.")
sys.exit(1)
print("Steady state confirmado. Seguro continuar.")
- Código complementario: el repo companion de chaos-engineering empaqueta los scripts de inyección de fallos, el manifiesto de Litmus, el verificador de steady state y la plantilla de game day.
Explicación
Cinco tipos de experimento de chaos:
- Infraestructura: Matar VMs, terminar contenedores, desconectar volúmenes
- Red: Inyectar latencia, descartar paquetes, particionar zonas
- Aplicación: Lanzar excepciones, devolver 503s, provocar memory leaks
- Estado: Llenar discos, corromper bases de datos, caducar certificados
- Dependencia: Hacer que las APIs aguas abajo den timeout o errores
El principio del radio de impacto:
- Empieza en staging, luego pasa a producción con tráfico mínimo
- Siempre con botón de aborto (rollback automático al violar SLO)
- Ejecuta en horario laboral con el equipo disponible
- Mide contra SLOs, no solo “¿se cae?”
El steady state es la pieza que la mayoría de equipos se salta: si no puedes cuantificar el comportamiento normal — error rate típico, latencia p99, peticiones por segundo — el experimento no te dice nada, porque no hay línea base que romper. El script de verificación de arriba existe exactamente para eso: ejecútalo antes del fallo, durante y tras la limpieza, y solo acepta un “pasa” cuando las tres corridas sean idénticas.
Variantes
| Herramienta | Plataforma | Tipos de Experimento |
|---|---|---|
| Chaos Monkey | AWS/Netflix | Terminación de instancias |
| Litmus | Kubernetes | Pod, red, disco, estrés |
| Gremlin | Multi-cloud | CPU, memoria, red, estado |
| AWS FIS | AWS | Fallos de EC2, ECS, EKS, RDS |
| Toxiproxy | Cualquiera | Latencia de red, timeouts |
Plantilla de Runbook de Game Day
# Game Day: <Fecha>
## Participantes
- Facilitador: <nombre>
- Observadores: <nombres>
- Ingeniero on-call: <nombre>
## Alcance
- Servicio objetivo: payment-service
- Entorno: staging
- Radio de impacto: 10% del tráfico
## Experimentos
1. Matar pod de base de datos primario - esperar failover < 30s
2. Inyectar 500ms de latencia al gateway de pagos - esperar p99 < 2s
3. Descartar 20% de paquetes a Redis - esperar solo aumento de cache miss
## Criterios de Aborto
- Error rate > 1% durante > 2 minutos
- Latencia p99 > 5s
- Cualquier corrupción de datos detectada
## Plan de Rollback
- `kubectl rollout undo deployment/payment-service`
- `toxiproxy-cli toxic delete --all`
- Paginar al ingeniero on-call
Lo que Funciona
- Mide antes de romper nada. Sin una línea base registrada de error rate, latencia y throughput, un experimento produce números sin nada con qué compararlos.
- Escribe la hipótesis. “Si matamos la base de datos primaria, el failover completa en <30s” es testeable; “a ver qué pasa” no es un experimento.
- Conecta el botón de aborto a la monitorización. El experimento debería detenerse solo en cuanto el error rate cruce tu umbral — no dependas de alguien mirando un dashboard.
- Programa game days. Un evento de chaos trimestral con todo el equipo en la sala (facilitador, observadores, on-call) genera mucha más confianza que las pruebas ad-hoc.
- Cada experimento cambia algo. Si una ejecución no produce una actualización de runbook o un fix de arquitectura, o no mediste nada o no aprendiste nada.
Errores Comunes
- Inyectar fallos que no puedes ver. Si tus dashboards no muestran el radio de impacto, no estás experimentando — solo estás rompiendo cosas. Deja la observabilidad bien antes del primer ataque.
- Ir directo a producción. Staging no es un ensayo, es la prueba de que tu experimento es supervivible. Gánate el chaos en producción con corridas limpias en staging.
- Sin forma de pararlo. Un experimento sin aborto funcional es una caída que agendaste tú mismo. Prueba el camino de rollback antes que el fallo.
- Mirar solo el fallo. La mitad del valor está en la recuperación: ¿la auto-curación realmente cura, o solo escribe una línea bonita en el log?
- Un solo radio de impacto: todo. Si un experimento puede tocar a todos los clientes, el radio es demasiado grande. Divídelo — 10% del tráfico, una AZ, una dependencia.
- Correr experimentos sin línea base. Necesitas métricas de steady state antes del chaos para comparar:
# Registrar línea base antes del experimento
curl -s https://api.example.com/metrics > baseline-metrics.json
# Correr experimento
# Comparar después
curl -s https://api.example.com/metrics > post-experiment-metrics.json
diff <(jq '.latency_p99' baseline-metrics.json) <(jq '.latency_p99' post-experiment-metrics.json)
- No limpiar tras los experimentos. Los toxics de Toxiproxy, las reglas tc y los fallos inyectados persisten si no se eliminan:
# Siempre limpiar
tc qdisc del dev eth0 root 2>/dev/null
toxiproxy-cli toxic delete --all
kubectl delete chaosengine --all -n staging
Consejos de Rendimiento
- Corre experimentos en horas valle. Incluso con radio de impacto estrecho, los experimentos añaden carga:
# Programar a las 2am cuando el tráfico es mínimo
0 2 * * * /usr/local/bin/chaos-experiment.sh
- Usa duraciones cortas. 30-60 segundos bastan para observar el comportamiento:
# Litmus: 30 segundos máximo
env:
- name: TOTAL_CHAOS_DURATION
value: '30'
- Paraleliza los checks de steady state. Comprueba varios endpoints a la vez:
import concurrent.futures
def check_all_endpoints(urls):
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
results = list(executor.map(check_endpoint, urls))
return all(results)
Véase También
Preguntas frecuentes
¿El chaos engineering es solo romper cosas al azar?
No — romper al azar te da incidentes, no datos. Un experimento de verdad tiene una hipótesis escrita, una línea base de steady state y un criterio de aborto antes de inyectar nada.
¿Cómo convenzo a la dirección para permitir chaos en producción?
Muéstrales staging primero, con hallazgos y las caídas que habrían sido. Un incidente controlado un martes por la tarde vale más que explicar uno sorpresa en Black Friday.
¿Qué diferencia hay entre chaos engineering y load testing?
El load testing responde "¿aguanta bajo tráfico?" El chaos responde "¿aguanta bajo fallos?" Un sistema puede superar el primero y colapsar igualmente en cuanto muere un solo pod.
¿Con qué frecuencia deberíamos correr experimentos de chaos?
Los game days mensuales en staging son un buen arranque. Cuando el equipo confíe en el proceso, automatiza corridas semanales en producción con radio de impacto estrecho — Netflix corre Chaos Monkey cada día laboral.
¿Qué métricas deberíamos monitorizar durante los experimentos?
Lo que ya miden tus SLOs: error rate (<1%), latencia p99 (dentro del SLO), throughput (no más de ~10% de caída) y tiempo de recuperación — cuánto tardas en volver al steady state.
¿Puede el chaos engineering funcionar sin Kubernetes?
Por supuesto. Gremlin y Toxiproxy corren en VMs, bare metal y contenedores; AWS FIS cubre EC2, ECS y RDS. Kubernetes simplemente hace cómodo el caos a nivel de pod.
¿Esta solución está lista para producción?
Las configs son reales pero deliberadamente conservadoras. Pruébalas en staging, conecta los criterios de aborto a tu monitorización, mantén el radio de impacto pequeño — y luego producción.
Recursos Relacionados
Chaos Engineering: Principios y Experimentos Seguros
Una guía práctica de chaos engineering: construye sistemas resilientes inyectando fallos intencionadamente. Los cinco principios, Litmus, Gremlin y Chaos Mesh.
GuideGuía de Pipelines CI/CD: Del Commit a Producción
Guía práctica para construir pipelines CI/CD con GitHub Actions, gates de testing, estrategias de despliegue y procedimientos de rollback.
RecipeRetry Backoff: Budgets, Deadlines y Config de Librerías
Implementa estrategias de retry resilientes con exponential backoff, jitter e integración de circuit breaker para recuperación de fallas transitorias.
RecipeEndpoint de Health Check
Cómo implementar un endpoint de health check listo para producción para monitoreo y load balancers.
RecipeRealizar Load Testing en APIs
Cómo simular tráfico realista, medir tiempos de respuesta e identificar cuellos de botella usando k6 y JMeter para APIs y servicios web.
RecipeTestear a Través de Múltiples OS y Versiones con GitHub
Cómo usar GitHub Actions matrix strategy para testear a través de múltiples sistemas operativos, versiones de lenguajes y configuraciones con include, exclude y matrices dinámicas.