Zum Inhalt springen

Chaos Engineering: Dinge absichtlich kaputt machen

Chaos Engineering ist die Praxis, absichtlich Fehler in Produktionssysteme zu injizieren, um Schwachstellen zu entdecken, bevor sie echte Ausfälle verursachen.

3 Min. Lesezeit
Ablauf eines Chaos-Engineering-Experiments mit den Phasen Hypothese, Experiment und Analyse

Dein System sieht auf dem Papier resilient aus — Retries, Circuit Breaker, redundante Datenbanken. Aber übersteht es tatsächlich Ausfälle? Chaos Engineering beantwortet diese Frage, indem es in kontrollierten Experimenten gezielt Fehler injiziert. Statt bei Ausfällen um 3 Uhr morgens Schwachstellen zu entdecken, findest du sie um 14 Uhr an einem Dienstag, wenn das ganze Team wach ist.

Das Chaos-Experiment-Framework

Jedes Chaos-Experiment folgt einer wissenschaftlichen Struktur: Hypothese aufstellen, Steady State definieren, Fehler injizieren, beobachten und analysieren.

tstypescript
// Structure of a chaos experiment
interface ChaosExperiment {
  name: string;
  hypothesis: string;
  steadyState: {
    metric: string;
    threshold: number;
    window: string;
  };
  method: {
    type: "latency" | "failure" | "resource" | "network";
    target: string;
    parameters: Record<string, unknown>;
    duration: string;
  };
  rollback: {
    automatic: boolean;
    trigger: string;
  };
}
 
const experiment: ChaosExperiment = {
  name: "Database failover under load",
  hypothesis: "When the primary database becomes unreachable, the application fails over to the replica within 30 seconds with less than 1% error rate increase",
  steadyState: {
    metric: "error_rate",
    threshold: 0.01,  // 1% error rate
    window: "5m",
  },
  method: {
    type: "network",
    target: "primary-db.internal",
    parameters: { action: "block", port: 5432 },
    duration: "5m",
  },
  rollback: {
    automatic: true,
    trigger: "error_rate > 0.05 for 2m",  // Abort if error rate exceeds 5%
  },
};

Einfach anfangen: Experimente auf Anwendungsebene

Du brauchst keinen Produktionstraffic und keine ausgefeilten Tools, um anzufangen. Beginne mit kontrollierten Experimenten in einer Staging-Umgebung.

tstypescript
// Middleware that simulates downstream service failures
// Only active when CHAOS_MODE environment variable is set
function chaosMiddleware(serviceName: string) {
  return (req: Request, res: Response, next: NextFunction) => {
    if (process.env.CHAOS_MODE !== "true") {
      return next();
    }
 
    const chaosConfig = getChaosConfig(serviceName);
 
    // Simulate latency injection
    if (chaosConfig.latency && Math.random() < chaosConfig.latency.probability) {
      const delay = chaosConfig.latency.minMs +
        Math.random() * (chaosConfig.latency.maxMs - chaosConfig.latency.minMs);
      setTimeout(next, delay);
      return;
    }
 
    // Simulate error injection
    if (chaosConfig.error && Math.random() < chaosConfig.error.probability) {
      res.status(chaosConfig.error.statusCode).json({
        error: "Chaos injection: simulated failure",
        service: serviceName,
      });
      return;
    }
 
    next();
  };
}

Experimente mit Netzwerkpartitionen

Netzwerkausfälle zwischen Services sind das häufigste Problem in der Produktion. Nutze tc (Traffic Control) unter Linux, um reale Netzwerkbedingungen zu simulieren.

shbash
# ❌ Testing only the happy path
# curl http://api-server:3000/health → 200 OK
# "Ship it, the service works!"
 
# ✅ Simulating real network conditions
 
# Add 200ms latency to traffic going to the database
tc qdisc add dev eth0 root netem delay 200ms 50ms distribution normal
 
# Simulate 10% packet loss to downstream service
tc qdisc add dev eth0 root netem loss 10%
 
# Simulate network partition (complete connectivity loss)
iptables -A OUTPUT -d database.internal -j DROP
 
# Clean up after experiment
tc qdisc del dev eth0 root
iptables -D OUTPUT -d database.internal -j DROP

Circuit Breaker validieren

Circuit Breaker sollen kaskadierende Ausfälle verhindern. Chaos-Experimente verifizieren, dass sie tatsächlich funktionieren.

tstypescript
// ❌ Assuming the circuit breaker works because the code looks right
const breaker = new CircuitBreaker(callExternalService, {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 30000,
});
 
// ✅ Chaos experiment to verify circuit breaker behavior
async function verifyCiruitBreaker() {
  const metrics = {
    totalRequests: 0,
    successfulRequests: 0,
    circuitOpenRejections: 0,
    timeouts: 0,
  };
 
  // Phase 1: Normal operation — circuit should be closed
  console.log("Phase 1: Verifying normal operation");
  for (let i = 0; i < 100; i++) {
    try {
      await breaker.fire();
      metrics.successfulRequests++;
    } catch (error) {
      // Should not happen in normal operation
    }
    metrics.totalRequests++;
  }
 
  // Phase 2: Inject failures — circuit should open
  console.log("Phase 2: Injecting failures");
  enableChaosMode({ error: { probability: 1.0, statusCode: 500 } });
 
  for (let i = 0; i < 50; i++) {
    try {
      await breaker.fire();
    } catch (error) {
      if (error.message === "Breaker is open") {
        metrics.circuitOpenRejections++;
      } else {
        metrics.timeouts++;
      }
    }
    metrics.totalRequests++;
  }
 
  // Phase 3: Recovery — circuit should close after reset timeout
  console.log("Phase 3: Verifying recovery");
  disableChaosMode();
  await sleep(35000); // Wait for reset timeout
 
  const recovered = await breaker.fire();
  console.log("Circuit recovered:", recovered !== undefined);
 
  return metrics;
}

Gameday-Übungen

Ein Gameday ist eine geplante Teamübung, bei der du Chaos-Experimente durchführst und die Incident Response übst. Er kombiniert technische Tests mit der Validierung von Prozessen.

markdownmarkdown
## Gameday Checklist
 
### Before
- [ ] Define 3-5 specific experiments with hypotheses
- [ ] Ensure monitoring dashboards are visible to all participants
- [ ] Verify rollback procedures for each experiment
- [ ] Brief all participants on the plan and abort criteria
- [ ] Confirm the on-call rotation is staffed
 
### During
- [ ] Run one experiment at a time
- [ ] Record observations in a shared document
- [ ] Note any unexpected behaviors or cascading effects
- [ ] Use the incident response process (even if the "incident" is planned)
- [ ] Abort immediately if abort criteria are met
 
### After
- [ ] Document findings for each experiment
- [ ] File tickets for discovered issues (with severity based on blast radius)
- [ ] Update runbooks based on what was learned
- [ ] Schedule follow-up gameday to verify fixes

Kontrolle des Blast Radius

Führe niemals unbegrenzte Chaos-Experimente durch. Definiere Abgrenzungen des Geltungsbereichs und automatische Abbruchbedingungen.

ymlyaml
# Chaos experiment configuration with safety controls
experiment:
  name: "API latency injection"
  scope:
    environment: "production"
    percentage_of_traffic: 5    # Only affect 5% of requests
    target_service: "order-api"
    excluded_endpoints:         # Never inject chaos on critical paths
      - "/api/payments"
      - "/api/health"
 
  abort_conditions:
    - metric: "error_rate"
      threshold: 0.05           # Abort if errors exceed 5%
      window: "2m"
    - metric: "p99_latency_ms"
      threshold: 5000           # Abort if p99 exceeds 5 seconds
      window: "2m"
 
  duration: "15m"
  auto_rollback: true

Die wichtigsten Erkenntnisse

  1. Chaos Engineering ist hypothesengetrieben — definiere, was du erwartest, bevor du Fehler injizierst
  2. Starte im Staging mit einfachen Experimenten — du brauchst keinen Chaos in der Produktion ab Tag eins
  3. Verifiziere deine Resilienz-Muster — Circuit Breaker, Retries und Failover funktionieren nur, wenn du sie testest
  4. Kontrolliere den Blast Radius aggressiv — begrenze immer den Geltungsbereich, setze Abbruchbedingungen und halte ein Rollback bereit
  5. Gamedays trainieren das Muskelgedächtnis des Teams — übe die Incident Response, wenn der Einsatz niedrig ist
  6. Behebe sofort, was du findest — eine entdeckte Schwachstelle ohne Fix ist schlimmer als Unwissenheit, weil du das Risiko akzeptiert hast
Wilfredo Rujel

Wilfredo Rujel

Full-Stack-Softwareentwickler

Diesen Beitrag teilenX