Skip to content

Inyección de fallos ​

La inyección de fallos es una técnica que introduce intencionadamente fallos para probar la resiliencia del sistema.

Tabla de contenido ​

  1. ¿Por qué la inyección de fallos?
  2. Cuándo usar la inyección de fallos
  3. Descripción general de la inyección de fallos
  4. Inyección de retraso
  5. Inyección de aborto
  6. Ejemplos prácticos
  7. Escenarios del mundo real
  8. Estrategias de prueba
  9. Mejores prácticas

¿Por qué la inyección de fallos? ​

Prueba de resiliencia en entornos de producción ​

En la arquitectura de microservicios, numerosos servicios dependen unos de otros, y un único fallo de servicio puede afectar a todo el sistema. La inyección de fallos es esencial por los siguientes motivos:

1. Principio fundamental de Chaos Engineering ​

Chaos Engineering, originado a partir de Chaos Monkey de Netflix, tiene como objetivo experimentar fallos de forma proactiva en entornos de producción y descubrir las debilidades del sistema.

2. Reproducción de escenarios reales de producción ​

En entornos de producción, pueden ocurrir los siguientes problemas:

EscenarioCausaPrueba de inyección de fallos
Latencia de redLatencia de red entre regionesInyección de retraso
Tiempo de espera del ServiceConsultas lentas a la base de datosInyección de retraso
Fallo temporalReinicio del Service, scale downInyección de aborto
Fallo parcialSolo fallan algunos podsInyección basada en porcentaje
Fallo en cascadaEl fallo de un Service se propaga a otrosInyección de fallos combinada

3. Verificación de la configuración de Circuit Breaker y Timeout ​

Sin inyección de fallos, es difícil confirmar si la configuración de Circuit Breaker y Timeout funciona realmente.

4. Validación de Deployments seguros ​

Al implementar nuevas versiones, puede verificar si son seguras incluso cuando fallan los servicios dependientes:

  • ¿La nueva versión gestiona correctamente los tiempos de espera?
  • ¿Realiza una degradación gradual cuando fallan los servicios dependientes?
  • ¿La lógica de gestión de errores funciona correctamente?

Cuándo usar la inyección de fallos ​

La inyección de fallos debe utilizarse en las siguientes situaciones:

1. Entornos de desarrollo y prueba ​

Escenario: desarrollo de un nuevo microservicio ​

yaml
# Inject faults into service under development
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payment-service-dev
  namespace: dev
spec:
  hosts:
  - payment-service
  http:
  - match:
    - headers:
        x-testing:
          exact: "true"  # Apply only to test traffic
    fault:
      delay:
        percentage:
          value: 50.0
        fixedDelay: 3s
      abort:
        percentage:
          value: 20.0
        httpStatus: 503
    route:
    - destination:
        host: payment-service
        subset: v2

Caso de uso:

  • Probar cómo reacciona el Service de pedidos cuando el Service de pagos se ralentiza o falla
  • Verificar que se muestren mensajes de error adecuados a los usuarios

2. Pruebas de integración en el entorno de Staging ​

Escenario: verificación final antes del Deployment en producción ​

yaml
# Inject random faults into all dependent services
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: database-service-staging
spec:
  hosts:
  - database-service
  http:
  - fault:
      delay:
        percentage:
          value: 10.0  # 10% of requests delayed
        fixedDelay: 5s
      abort:
        percentage:
          value: 5.0   # 5% of requests fail
        httpStatus: 500
    route:
    - destination:
        host: database-service

Caso de uso:

  • Verificar la resiliencia de todo el sistema antes del Deployment en producción
  • Confirmar que las alertas de monitoreo funcionen correctamente

3. Pruebas de Chaos en el entorno de producción ​

Escenario: pruebas periódicas de resiliencia en producción ​

yaml
# Inject faults at very low rate in production
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: recommendation-service-prod
spec:
  hosts:
  - recommendation-service
  http:
  - match:
    - headers:
        x-canary:
          exact: "true"  # Apply only to canary users
    fault:
      abort:
        percentage:
          value: 1.0  # Only 1% of requests fail
        httpStatus: 503
    route:
    - destination:
        host: recommendation-service

Caso de uso:

  • Chaos Engineering al estilo de Netflix
  • Verificar la capacidad de respuesta ante fallos reales en producción
  • Nota: Comience con tasas muy bajas (1-5%) y supervise el impacto

4. Ajuste de políticas de Timeout y Retry ​

Escenario: búsqueda de valores de Timeout óptimos ​

yaml
# Test with various delay times
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: search-service-timeout-test
spec:
  hosts:
  - search-service
  http:
  - match:
    - headers:
        x-test-scenario:
          exact: "slow-response"
    fault:
      delay:
        percentage:
          value: 100.0
        fixedDelay: 10s  # 10 second delay
    timeout: 5s  # 5 second timeout setting
    route:
    - destination:
        host: search-service

Caso de uso:

  • Probar si la configuración actual de Timeout (5 segundos) es adecuada
  • Verificar que el Timeout funcione cuando hay un retraso de 10 segundos
  • Encontrar un valor óptimo que no perjudique la experiencia del usuario

5. Verificación del funcionamiento de Circuit Breaker ​

Escenario: confirmar que Circuit Breaker funciona correctamente ​

yaml
# DestinationRule: Circuit Breaker configuration
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews-circuit-breaker
spec:
  host: reviews
  trafficPolicy:
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 30s
---
# VirtualService: Fault injection
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews-fault
spec:
  hosts:
  - reviews
  http:
  - fault:
      abort:
        percentage:
          value: 60.0  # 60% failure rate
        httpStatus: 503
    route:
    - destination:
        host: reviews

Caso de uso:

  • Verificar que Circuit Breaker se active después de 5 errores consecutivos con una tasa de fallos del 60%
  • Validar la recuperación automática después de 30 segundos

6. Pruebas para grupos de usuarios específicos ​

Escenario: inyectar fallos solo para beta testers ​

yaml
# Inject faults only for specific users
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: api-service-beta
spec:
  hosts:
  - api-service
  http:
  - match:
    - headers:
        end-user:
          exact: "beta-tester"  # Beta testers only
    fault:
      delay:
        percentage:
          value: 20.0
        fixedDelay: 2s
    route:
    - destination:
        host: api-service
  - route:  # Normal routing for regular users
    - destination:
        host: api-service

Caso de uso:

  • Probar de forma segura sin afectar a los usuarios reales
  • Mejorar a partir de los comentarios de los beta testers

Descripción general de la inyección de fallos ​

Inyección de retraso ​

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews-delay
spec:
  hosts:
  - reviews
  http:
  - fault:
      delay:
        percentage:
          value: 10.0  # Inject delay in 10% of requests
        fixedDelay: 5s  # 5 second delay
    route:
    - destination:
        host: reviews

Inyección de aborto ​

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews-abort
spec:
  hosts:
  - reviews
  http:
  - fault:
      abort:
        percentage:
          value: 10.0  # Abort 10% of requests
        httpStatus: 503  # Return HTTP 503 error
    route:
    - destination:
        host: reviews

Ejemplos prácticos ​

1. Combinación de retraso y aborto ​

En entornos de producción reales, los retrasos y los fallos pueden ocurrir simultáneamente:

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: ratings-combined-fault
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percentage:
          value: 20.0  # 20% of requests delayed
        fixedDelay: 3s
      abort:
        percentage:
          value: 10.0  # 10% of requests fail
        httpStatus: 503
    route:
    - destination:
        host: ratings

Resultado:

  • El 20% de las solicitudes recibe un retraso de 3 segundos
  • El 10% de las solicitudes recibe un error 503 inmediato
  • El 70% restante se procesa normalmente

2. Inyección de fallos condicional ​

Inyecte fallos solo bajo condiciones específicas:

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews-conditional-fault
spec:
  hosts:
  - reviews
  http:
  # Inject faults only for mobile users
  - match:
    - headers:
        user-agent:
          regex: ".*Mobile.*"
    fault:
      delay:
        percentage:
          value: 30.0
        fixedDelay: 2s
    route:
    - destination:
        host: reviews
        subset: v2
  # Normal routing for regular users
  - route:
    - destination:
        host: reviews
        subset: v1

3. Inyección progresiva de fallos ​

Pruebe aumentando gradualmente la tasa de fallos:

yaml
# Stage 1: 5% faults
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: api-fault-stage1
spec:
  hosts:
  - api-service
  http:
  - fault:
      abort:
        percentage:
          value: 5.0
        httpStatus: 500
    route:
    - destination:
        host: api-service
---
# Stage 2: 10% faults (apply after monitoring)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: api-fault-stage2
spec:
  hosts:
  - api-service
  http:
  - fault:
      abort:
        percentage:
          value: 10.0
        httpStatus: 500
    route:
    - destination:
        host: api-service
---
# Stage 3: 20% faults (apply after sufficient validation)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: api-fault-stage3
spec:
  hosts:
  - api-service
  http:
  - fault:
      abort:
        percentage:
          value: 20.0
        httpStatus: 500
    route:
    - destination:
        host: api-service

4. Pruebas por código de estado HTTP ​

Pruebe con varios códigos de error HTTP:

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payment-error-scenarios
spec:
  hosts:
  - payment-service
  http:
  # Scenario 1: Service overload (503)
  - match:
    - headers:
        x-test-scenario:
          exact: "overload"
    fault:
      abort:
        percentage:
          value: 50.0
        httpStatus: 503
    route:
    - destination:
        host: payment-service
  # Scenario 2: Internal server error (500)
  - match:
    - headers:
        x-test-scenario:
          exact: "server-error"
    fault:
      abort:
        percentage:
          value: 30.0
        httpStatus: 500
    route:
    - destination:
        host: payment-service
  # Scenario 3: Gateway timeout (504)
  - match:
    - headers:
        x-test-scenario:
          exact: "timeout"
    fault:
      abort:
        percentage:
          value: 20.0
        httpStatus: 504
    route:
    - destination:
        host: payment-service
  # Default routing
  - route:
    - destination:
        host: payment-service

Escenarios del mundo real ​

Escenario 1: simulación de consultas lentas a la base de datos ​

Situación: las consultas a la base de datos se vuelven lentas de forma intermitente

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: database-slow-query
  namespace: production
spec:
  hosts:
  - database-service
  http:
  - fault:
      delay:
        percentage:
          value: 15.0  # 15% of queries are slow
        fixedDelay: 8s   # 8 second delay
    route:
    - destination:
        host: database-service

Objetivos de prueba:

  1. ¿Es adecuada la configuración de Timeout de la aplicación?
  2. ¿Se agota el connection pool?
  3. ¿Se muestran mensajes de error adecuados a los usuarios?

Resultados esperados:

  • Un Timeout adecuado permite un fallo rápido (fail-fast)
  • Gestión normal del connection pool
  • Retraso en la respuesta de todo el sistema -> se necesita Circuit Breaker

Escenario 2: prueba de fallo en cascada de microservicios ​

Situación: verificar si el fallo de un Service se propaga a otros servicios

yaml
# Inject faults into payment service
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payment-cascade-test
spec:
  hosts:
  - payment-service
  http:
  - fault:
      abort:
        percentage:
          value: 30.0  # 30% failure
        httpStatus: 503
    route:
    - destination:
        host: payment-service
---
# Configure Circuit Breaker for order service
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: order-circuit-breaker
spec:
  host: order-service
  trafficPolicy:
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 30s

Objetivos de prueba:

  1. ¿El Service de pedidos gestiona correctamente el fallo de pago?
  2. ¿Se activa Circuit Breaker para que el Service de inventario funcione normalmente?
  3. ¿Se muestran mensajes adecuados al usuario en el frontend?

Escenario 3: prueba de situación de límite de tasa de API ​

Situación: simular que una API externa alcanza el límite de tasa

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: external-api-rate-limit
spec:
  hosts:
  - external-api-service
  http:
  - match:
    - headers:
        x-api-key:
          exact: "test-key"
    fault:
      abort:
        percentage:
          value: 40.0  # 40% of requests rate limited
        httpStatus: 429  # Too Many Requests
    route:
    - destination:
        host: external-api-service

Objetivos de prueba:

  1. ¿Los errores 429 se gestionan adecuadamente?
  2. ¿La lógica de Retry usa Exponential Backoff?
  3. ¿Se utiliza caché para reducir las llamadas a la API?

Escenario 4: simulación de latencia de red entre regiones ​

Situación: latencia al llamar a servicios en regiones diferentes

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: cross-region-latency
spec:
  hosts:
  - us-east-service
  http:
  - match:
    - sourceLabels:
        region: "eu-west"  # Calling from EU to US
    fault:
      delay:
        percentage:
          value: 100.0
        fixedDelay: 150ms  # 150ms delay (transatlantic)
    route:
    - destination:
        host: us-east-service

Objetivos de prueba:

  1. Confirmar el impacto de la latencia entre regiones en servicios globales
  2. Determinar si es posible optimizar mediante caché o CDN
  3. ¿Se cumple el objetivo de SLA (p. ej., 95% de las solicitudes en menos de 500 ms)?

Escenario 5: simulación de fallo temporal durante el Deployment ​

Situación: algunos pods no están disponibles temporalmente durante Rolling Update

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: deployment-transient-failure
spec:
  hosts:
  - app-service
  http:
  - match:
    - headers:
        x-deployment-test:
          exact: "true"
    fault:
      abort:
        percentage:
          value: 25.0  # 25% pods fail (1 out of 4)
        httpStatus: 503
      delay:
        percentage:
          value: 10.0
        fixedDelay: 5s   # Some start slowly
    route:
    - destination:
        host: app-service
        subset: v2

Objetivos de prueba:

  1. Mantener la disponibilidad durante el Deployment (mínimo 75%)
  2. ¿Readiness Probe funciona correctamente?
  3. ¿Load Balancer enruta el tráfico solo a pods saludables?

Estrategias de prueba ​

1. Chaos Engineering progresivo ​

Aumente gradualmente la tasa de fallos para encontrar los límites del sistema:

Ejecución paso a paso:

bash
# Stage 1: 1% fault injection
kubectl apply -f fault-injection-1percent.yaml
# Monitor for 15 minutes
kubectl logs -f deployment/monitoring

# If no issues, proceed to stage 2
kubectl apply -f fault-injection-5percent.yaml
# Monitor for 15 minutes

# Continue...

2. Pruebas basadas en el tiempo ​

Inyecte fallos solo durante períodos de tiempo específicos:

yaml
# Automate with CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
  name: fault-injection-scheduler
spec:
  schedule: "0 2 * * *"  # Every day at 2 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: apply-fault
            image: bitnami/kubectl
            command:
            - /bin/sh
            - -c
            - |
              kubectl apply -f /config/fault-injection.yaml
              sleep 3600  # Maintain for 1 hour
              kubectl delete -f /config/fault-injection.yaml

3. Pipeline de pruebas automatizadas ​

Intégrelo en el pipeline de CI/CD:

yaml
# GitLab CI example
stages:
  - deploy
  - fault-injection-test
  - verify
  - cleanup

fault_injection_test:
  stage: fault-injection-test
  script:
    # Apply Fault Injection
    - kubectl apply -f tests/fault-injection.yaml

    # Run load test
    - k6 run --vus 100 --duration 5m tests/load-test.js

    # Validate metrics
    - |
      ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(istio_requests_total{response_code=\"500\"}[5m])" | jq '.data.result[0].value[1]')
      if [ $(echo "$ERROR_RATE > 0.05" | bc) -eq 1 ]; then
        echo "Error rate too high: $ERROR_RATE"
        exit 1
      fi
  after_script:
    # Remove Fault Injection
    - kubectl delete -f tests/fault-injection.yaml

4. Monitoreo y alertas ​

Supervise las métricas clave durante la inyección de fallos:

yaml
# Prometheus alert rules
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-alerts
data:
  fault-injection-alerts.yaml: |
    groups:
    - name: fault-injection
      rules:
      # Error rate increase
      - alert: HighErrorRate
        expr: rate(istio_requests_total{response_code=~"5.."}[5m]) > 0.1
        for: 2m
        annotations:
          summary: "High error rate during fault injection"

      # Circuit Breaker activation
      - alert: CircuitBreakerOpen
        expr: envoy_cluster_circuit_breakers_default_rq_open > 0
        for: 1m
        annotations:
          summary: "Circuit breaker opened"

      # Response time increase
      - alert: HighLatency
        expr: histogram_quantile(0.95, rate(istio_request_duration_milliseconds_bucket[5m])) > 3000
        for: 5m
        annotations:
          summary: "95th percentile latency > 3s"

5. Inyección de fallos Blue-Green ​

Inyecte fallos en el entorno Blue y compárelo con el entorno Green:

yaml
# Blue environment: Fault Injection
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: app-blue-fault
spec:
  hosts:
  - app-service
  http:
  - match:
    - headers:
        x-version:
          exact: "blue"
    fault:
      delay:
        percentage:
          value: 20.0
        fixedDelay: 3s
    route:
    - destination:
        host: app-service
        subset: blue
---
# Green environment: Normal
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: app-green-normal
spec:
  hosts:
  - app-service
  http:
  - match:
    - headers:
        x-version:
          exact: "green"
    route:
    - destination:
        host: app-service
        subset: green

Métricas de comparación:

  • Tasa de errores
  • Tiempo de respuesta (P50, P95, P99)
  • Indicadores de experiencia del usuario

Mejores prácticas ​

1. Comience poco a poco ​

  • Comience inicialmente con tasas bajas de 1-5%
  • Pruebe exhaustivamente en entornos de desarrollo/Staging
  • Ejecute en producción durante períodos de bajo impacto empresarial

2. El monitoreo es esencial ​

Prepare el dashboard de monitoreo antes de aplicar la inyección de fallos:

yaml
# Grafana dashboard metrics
- istio_requests_total (Error rate)
- istio_request_duration_milliseconds (Latency)
- envoy_cluster_upstream_rq_retry (Retry count)
- envoy_cluster_circuit_breakers_* (Circuit Breaker status)

3. Use etiquetas claras ​

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payment-fault
  labels:
    fault-injection: "true"
    test-type: "chaos-engineering"
    test-date: "2025-01-15"
  annotations:
    description: "Testing payment service resilience"
    owner: "platform-team"

4. Mecanismo de rollback automático ​

bash
#!/bin/bash
# Apply Fault Injection
kubectl apply -f fault-injection.yaml

# Monitor for 5 minutes
sleep 300

# Check error rate
ERROR_RATE=$(kubectl exec -it prometheus-pod -- \
  promtool query instant \
  'rate(istio_requests_total{response_code="500"}[5m])' | \
  jq '.data.result[0].value[1]')

# Rollback if threshold exceeded
if [ $(echo "$ERROR_RATE > 0.1" | bc) -eq 1 ]; then
  echo "Error rate too high, rolling back..."
  kubectl delete -f fault-injection.yaml
  exit 1
fi

5. Documentación ​

Documente todas las pruebas de inyección de fallos:

yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: api-fault-test
  annotations:
    # Test purpose
    test-purpose: "Verify Circuit Breaker activation"

    # Expected behavior
    expected-behavior: |
      - Circuit Breaker opens after 5 consecutive errors
      - Requests fail fast with 503 error
      - System recovers after 30 seconds

    # Success criteria
    success-criteria: |
      - Error rate < 5%
      - P95 latency < 500ms
      - No cascading failures

    # Rollback plan
    rollback-plan: "kubectl delete vs api-fault-test"

6. Precauciones para el entorno de producción ​

  • Evaluación del impacto empresarial: Analice el impacto de la inyección de fallos en los usuarios reales
  • Expansión gradual: Aumente lentamente de 1% -> 5% -> 10%
  • Configuración de alertas: Alertas inmediatas cuando se superen los umbrales
  • Preparación para rollback: Esté listo para realizar rollback inmediatamente en cualquier momento
  • Evite el horario laboral: Elija períodos con poco tráfico

7. Pruebas periódicas ​

yaml
# Weekly automated Chaos Test
apiVersion: batch/v1
kind: CronJob
metadata:
  name: weekly-chaos-test
spec:
  schedule: "0 3 * * 0"  # Every Sunday at 3 AM
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: chaos-tester
          containers:
          - name: chaos-test
            image: chaos-tester:latest
            env:
            - name: FAULT_PERCENTAGE
              value: "5"
            - name: DURATION
              value: "1h"

Referencias ​

Pregunta a la documentación

Enter envía, Shift+Enter añade una línea.