Zum Inhalt

Traffic Splitting Anleitung

Umfassende Anleitung für A/B Testing, Canary Deployments und Traffic Splitting in GAL (Gateway Abstraction Layer)

Inhaltsverzeichnis

  1. Übersicht
  2. Schnellstart
  3. Konfigurationsoptionen
  4. Provider-Implementierung
  5. Häufige Anwendungsfälle
  6. Best Practices
  7. Traffic Splitting Testen
  8. Troubleshooting

Übersicht

Traffic Splitting ist ein essentielles Feature für moderne Deployment-Strategien wie Canary Deployments, A/B Testing und Blue/Green Deployments. GAL bietet eine einheitliche Traffic Splitting-Konfiguration für alle unterstützten Gateway-Provider.

Was ist Traffic Splitting?

Traffic Splitting verteilt eingehende Requests auf verschiedene Backend-Versionen basierend auf Gewichtungen, Headers oder Cookies. Dies ermöglicht kontrollierte Rollouts neuer Features ohne Risiko für alle Nutzer.

Traffic Splitting Strategien:

Weight-based:  90% → Stable, 10% → Canary
Header-based:  X-Version: beta → Beta Backend
Cookie-based:  canary_user=true → Canary Backend

Warum ist Traffic Splitting wichtig?

  • Risikofreie Deployments: Neue Versionen schrittweise ausrollen
  • A/B Testing: Feature-Varianten mit echten Nutzern testen
  • Canary Deployments: Kleine Nutzergruppen als "Kanarienvögel"
  • Blue/Green Deployments: Sofortiges Switching zwischen Versionen
  • Feature Flags: Header-basierte Feature-Freischaltung
  • User Segmentation: Verschiedene Nutzergruppen testen unterschiedliche Features

Provider-Unterstützung

Feature Envoy Kong APISIX Traefik Nginx HAProxy Azure APIM AWS API GW GCP API GW
Traffic Splitting
Weight-based
Header-based ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
Cookie-based ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
Dynamic Weights

Coverage: 88.9% (8 von 9 Providern haben Unterstützung)

Open-Source Providers: - Envoy: Weighted Clusters ✅ - Kong: Weighted Upstream Targets (0-1000 scale) ✅ - APISIX: Native traffic-split Plugin ✅ - Traefik: WeightedRoundRobin Services ✅ - Nginx: set_random + conditional routing ✅ - HAProxy: Weighted Servers (0-256 scale) ✅

Cloud Providers: - Azure APIM: Load-Balanced Backend Pool mit Gewichten ✅ - AWS API Gateway: VTL (Velocity Template Language) mit stageVariables ✅ - GCP API Gateway: ❌ Keine native Unterstützung (externe Cloud Load Balancer erforderlich)

Hinweis: Azure APIM und AWS API Gateway haben vollständige Weight-based Unterstützung. GCP API Gateway benötigt externe Cloud Load Balancer für Traffic Splitting.


Schnellstart

1. Einfaches Canary Deployment (90/10)

Verteile 90% Traffic auf stabile Version, 10% auf Canary:

version: "1.0"
provider: envoy

services:
  - name: api
    type: rest
    protocol: http
    upstream:
      host: placeholder  # Wird von traffic_split überschrieben
      port: 8080
    routes:
      - path_prefix: /api/v1
        methods: [GET, POST, PUT, DELETE]
        traffic_split:
          enabled: true
          targets:
            - name: stable
              weight: 90
              upstream:
                host: api-v1-stable
                port: 8080
              description: "Stable production version"
            - name: canary
              weight: 10
              upstream:
                host: api-v1-canary
                port: 8080
              description: "Canary deployment for testing"

Deployment:

gal generate -f gateway.yaml -o envoy.yaml

2. A/B Testing (50/50 Split)

Teste zwei Feature-Varianten mit gleichverteiltem Traffic:

services:
  - name: ab_testing_api
    type: rest
    protocol: http
    upstream:
      host: placeholder
      port: 8080
    routes:
      - path_prefix: /api/v2
        methods: [GET, POST]
        traffic_split:
          enabled: true
          targets:
            - name: version_a
              weight: 50
              upstream:
                host: api-v2-a
                port: 8080
              description: "Version A - existing algorithm"
            - name: version_b
              weight: 50
              upstream:
                host: api-v2-b
                port: 8080
              description: "Version B - new algorithm"

3. Header-based Beta Testing

Route Nutzer mit X-Version: beta Header zum Beta-Backend:

services:
  - name: beta_testing_api
    type: rest
    protocol: http
    upstream:
      host: placeholder
      port: 8080
    routes:
      - path_prefix: /api/beta
        methods: [GET, POST, PUT, DELETE]
        traffic_split:
          enabled: true
          targets:
            - name: production
              weight: 100
              upstream:
                host: api-prod
                port: 8080
            - name: beta
              weight: 0  # Nur via Header-Routing
              upstream:
                host: api-beta
                port: 8080
          routing_rules:
            header_rules:
              - header_name: "X-Version"
                header_value: "beta"
                target_name: "beta"
          fallback_target: "production"

Nutzung:

# Normale Nutzer → Production
curl http://api.example.com/api/beta

# Beta-Nutzer → Beta Backend
curl -H "X-Version: beta" http://api.example.com/api/beta

Route Nutzer mit spezifischem Cookie zum Canary-Backend:

services:
  - name: user_segment_api
    type: rest
    protocol: http
    upstream:
      host: placeholder
      port: 8080
    routes:
      - path_prefix: /api/users
        traffic_split:
          enabled: true
          targets:
            - name: stable
              weight: 100
              upstream:
                host: api-stable
                port: 8080
            - name: canary_users
              weight: 0  # Nur via Cookie
              upstream:
                host: api-canary
                port: 8080
          routing_rules:
            cookie_rules:
              - cookie_name: "canary_user"
                cookie_value: "true"
                target_name: "canary_users"
          fallback_target: "stable"

Konfigurationsoptionen

TrafficSplitConfig

Hauptkonfiguration für Traffic Splitting auf Route-Ebene.

traffic_split:
  enabled: true|false          # Traffic Splitting aktivieren
  targets: []                  # Liste von SplitTarget (min. 1)
  routing_rules:               # Optional: Header/Cookie Routing
    header_rules: []           # Header-basierte Regeln
    cookie_rules: []           # Cookie-basierte Regeln
  fallback_target: "name"      # Fallback bei nicht-matchenden Rules

SplitTarget

Einzelnes Backend-Ziel mit Gewichtung.

targets:
  - name: "stable"                # Eindeutiger Name (required)
    weight: 90                    # Gewichtung 0-100 (required)
    upstream:                     # Backend-Konfiguration (required)
      host: "api-stable"
      port: 8080
    description: "Stable version" # Optional

Validierung: - ✅ Gewichte müssen zwischen 0-100 sein - ✅ Summe aller Gewichte muss 100 sein (außer bei Routing Rules) - ✅ Target-Namen müssen eindeutig sein - ✅ Mindestens 1 Target erforderlich

Header-based Routing Rules

Route basierend auf HTTP-Headern.

routing_rules:
  header_rules:
    - header_name: "X-Version"    # HTTP Header (case-insensitive)
      header_value: "beta"        # Erwarteter Wert
      target_name: "beta"         # Ziel-Target
    - header_name: "X-Environment"
      header_value: "staging"
      target_name: "staging"

Priorität: Header Rules > Cookie Rules > Weight-based

Route basierend auf HTTP-Cookies.

routing_rules:
  cookie_rules:
    - cookie_name: "canary_user"  # Cookie-Name
      cookie_value: "true"        # Erwarteter Wert
      target_name: "canary"       # Ziel-Target
    - cookie_name: "user_tier"
      cookie_value: "premium"
      target_name: "premium_backend"

Provider-Implementierung

Envoy - Weighted Clusters

Envoy verwendet weighted_clusters für Traffic Splitting.

Generierte Konfiguration:

routes:
  - match:
      prefix: '/api/v1'
    route:
      weighted_clusters:
        clusters:
        - name: canary_deployment_api_stable_cluster
          weight: 90
        - name: canary_deployment_api_canary_cluster
          weight: 10
        total_weight: 100

clusters:
  - name: canary_deployment_api_stable_cluster
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: api-v1-stable
                port_value: 8080

Eigenschaften: - ✅ Exakte Gewichtungen (90% = weight 90) - ✅ Separate Cluster pro Target - ✅ Deterministisches Routing - ⚠️ Header/Cookie-Routing benötigt Lua-Filter

Deployment:

gal generate -f gateway.yaml -o envoy.yaml
envoy -c envoy.yaml

Nginx - set_random + Conditional Routing

Nginx verwendet set_random für probabilistische Verteilung.

Generierte Konfiguration:

location /api/v1 {
    # Weight-based traffic splitting
    set $split_backend '';
    # stable: 90% (cumulative: 90%)
    set_random $rand_split 0 100;
    if ($rand_split < 90) {
        set $split_backend 'stable';
        proxy_pass http://api-v1-stable:8080;
    }
    if ($split_backend = '') {
        set $split_backend 'canary';
        proxy_pass http://api-v1-canary:8080;
    }
}

# Header-based routing
location /api/beta {
    set $backend_target '';
    if ($http_x_version = 'beta') {
        set $backend_target 'beta';
    }
    if ($backend_target = 'beta') {
        proxy_pass http://api-beta:8080;
    }
}

Eigenschaften: - ✅ set_random für probabilistische Verteilung - ✅ Header-Routing via $http_* Variablen - ✅ Cookie-Routing via $cookie_* Variablen - ⚠️ Nicht session-persistent (jede Request neu) - ⚠️ Mehrere if-Statements (nicht optimal, aber funktional)

Kong - Weighted Upstream Targets

Kong verwendet Upstreams mit gewichteten Targets.

Generierte Konfiguration:

upstreams:
- name: canary_deployment_api_route0_upstream
  algorithm: round-robin
  targets:
  - target: api-v1-stable:8080
    weight: 900  # Kong: 0-1000 (90% = 900)
  - target: api-v1-canary:8080
    weight: 100  # Kong: 0-1000 (10% = 100)

services:
- name: canary_deployment_api
  protocol: http
  host: canary_deployment_api_route0_upstream
  routes:
  - name: canary_deployment_api_route
    paths:
    - /api/v1

Eigenschaften: - ✅ Gewichtungsskala 0-1000 (GAL 0-100 × 10) - ✅ Round-robin respektiert Gewichte - ✅ Dynamische Rekonfiguration via Admin API - ⚠️ 1 Service = 1 Upstream (Limitation) - ⚠️ Header/Cookie-Routing benötigt request-transformer Plugin

APISIX - traffic-split Plugin

APISIX hat natives traffic-split Plugin mit Rules.

Generierte Konfiguration:

{
  "routes": [{
    "plugins": {
      "traffic-split": {
        "rules": [
          {
            "match": [{
              "vars": [["http_x_version", "==", "beta"]]
            }],
            "weighted_upstreams": [{
              "upstream": {
                "name": "beta_testing_api_beta_upstream",
                "type": "roundrobin",
                "nodes": {"api-beta:8080": 1}
              },
              "weight": 1
            }]
          },
          {
            "weighted_upstreams": [
              {
                "upstream": {"nodes": {"api-prod:8080": 1}},
                "weight": 100
              },
              {
                "upstream": {"nodes": {"api-beta:8080": 1}},
                "weight": 0
              }
            ]
          }
        ]
      }
    }
  }]
}

Eigenschaften: - ✅ Native Plugin-Unterstützung - ✅ Rules mit match Conditions - ✅ Header-Matching (http_* vars) - ✅ Cookie-Matching (cookie_* vars) - ✅ Keine Lua benötigt - ✅ Dynamische Rekonfiguration via Admin API

Traefik - WeightedRoundRobin Services

Traefik verwendet weighted Services.

Generierte Konfiguration:

http:
  routers:
    canary_deployment_api_router_0:
      rule: 'PathPrefix(`/api/v1`)'
      service: canary_deployment_api_route0_service

  services:
    canary_deployment_api_route0_service:
      weighted:
        services:
        - name: canary_deployment_api_stable_service
          weight: 90
        - name: canary_deployment_api_canary_service
          weight: 10

    canary_deployment_api_stable_service:
      loadBalancer:
        servers:
        - url: 'http://api-v1-stable:8080'

    canary_deployment_api_canary_service:
      loadBalancer:
        servers:
        - url: 'http://api-v1-canary:8080'

Eigenschaften: - ✅ Native weighted Services - ✅ Saubere YAML-Struktur - ✅ Dynamische File Provider Rekonfiguration - ✅ Kompatibel mit Kubernetes IngressRoute - ⚠️ Header/Cookie-Routing benötigt separate Router mit Priority

HAProxy - Weighted Servers

HAProxy verwendet Server-Gewichte (0-256 scale).

Generierte Konfiguration:

backend backend_canary_deployment_api
    balance roundrobin
    option httpclose
    option forwardfor

    # Backend servers mit Gewichten
    server server_stable api-v1-stable:8080 check inter 10s fall 3 rise 2 weight 230
    server server_canary api-v1-canary:8080 check inter 10s fall 3 rise 2 weight 25

Eigenschaften: - ✅ Weighted Servers (0-256 scale) - ✅ Robustes Load Balancing - ✅ Health Checks integriert - ✅ Production-grade Performance - ⚠️ Weight-Umrechnung: GAL 0-100 → HAProxy 0-256 (×2.56) - ❌ Keine Header/Cookie-Routing Unterstützung

Deployment:

gal generate -f gateway.yaml -o haproxy.cfg --provider haproxy
haproxy -f haproxy.cfg -c  # Config validieren
haproxy -f haproxy.cfg     # Starten

Azure API Management - Load-Balanced Backend Pool

Azure APIM verwendet Load-Balanced Backend Pools mit Gewichten.

Generierte ARM Template Konfiguration:

{
  "type": "Microsoft.ApiManagement/service/backends",
  "properties": {
    "description": "Load-balanced backend pool for canary_deployment_api",
    "type": "pool",
    "pool": {
      "services": [
        {
          "id": "/backends/canary_deployment_api-stable-backend",
          "priority": 1,
          "weight": 90
        },
        {
          "id": "/backends/canary_deployment_api-canary-backend",
          "priority": 1,
          "weight": 10
        }
      ]
    }
  }
}

Policy XML:

<policies>
  <inbound>
    <base />
    <set-backend-service backend-id="canary_deployment_api-backend-pool" />
  </inbound>
</policies>

Eigenschaften: - ✅ Native Backend Pool Support - ✅ Weighted Targets (gleiche Scale wie GAL: 0-100) - ✅ Azure Portal Verwaltung - ✅ Multi-Region Deployment - ⚠️ Header/Cookie-Routing benötigt Policy XML - ⚠️ ARM Template Deployment erforderlich

Deployment:

gal generate -f gateway.yaml -o azure-apim.json --provider azure_apim
az deployment group create \
  --resource-group my-rg \
  --template-file azure-apim.json

AWS API Gateway - VTL (Velocity Template Language)

AWS API Gateway verwendet VTL Request Templates mit stageVariables.

Generierte OpenAPI 3.0 Konfiguration:

{
  "paths": {
    "/api/v1": {
      "get": {
        "x-amazon-apigateway-integration": {
          "type": "http_proxy",
          "httpMethod": "GET",
          "uri": "${stageVariables.backend_url}/api/v1",
          "requestTemplates": {
            "application/json": "## AWS API Gateway Traffic Splitting via VTL\\n#set($random = $context.requestTimeEpoch % 100)\\n#if($random < 90)\\n  #set($backend_url = $stageVariables.canary_deployment_api_stable_url)\\n#elseif($random < 100)\\n  #set($backend_url = $stageVariables.canary_deployment_api_canary_url)\\n#end\\n#set($context.requestOverride.path.backend_url = $backend_url)"
          }
        }
      }
    }
  }
}

Stage Variables:

{
  "canary_deployment_api_stable_url": "https://api-v1-stable.example.com:8080",
  "canary_deployment_api_canary_url": "https://api-v1-canary.example.com:8080"
}

Eigenschaften: - ✅ VTL Template Support - ✅ Weighted Routing via Random Selection - ✅ Stage Variables für Flexibilität - ✅ Deployment History & Rollback - ⚠️ Komplexe VTL Syntax - ⚠️ Stage Variables müssen manuell konfiguriert werden - ⚠️ Header/Cookie-Routing benötigt zusätzliche VTL Logic

Deployment:

gal generate -f gateway.yaml -o aws-apigateway.json --provider aws_apigateway

# Import OpenAPI
aws apigateway import-rest-api \
  --body file://aws-apigateway.json \
  --fail-on-warnings

# Deploy Stage mit Variables
aws apigateway create-deployment \
  --rest-api-id <api-id> \
  --stage-name prod \
  --variables canary_deployment_api_stable_url=https://api-stable:8080,canary_deployment_api_canary_url=https://api-canary:8080

GCP API Gateway - ❌ Nicht Unterstützt

GCP API Gateway unterstützt KEIN natives Traffic Splitting.

Grund: - GCP API Gateway unterstützt nur ein einzelnes Backend pro Route - Keine Weighted Targets oder Load Balancing Features - OpenAPI 2.0 (Swagger) hat keine Traffic Splitting Extensions

Workaround: Verwende Google Cloud Load Balancer VOR GCP API Gateway:

Client → Cloud Load Balancer (Traffic Split 90/10)
         ├─ 90% → Backend 1 (Stable)
         └─ 10% → Backend 2 (Canary)

Cloud Load Balancer Konfiguration:

# Weighted Backend Services
backends:
  - name: stable-backend
    backends:
      - group: instance-group-stable
        balancingMode: UTILIZATION
        capacityScaler: 0.9  # 90%
  - name: canary-backend
    backends:
      - group: instance-group-canary
        balancingMode: UTILIZATION
        capacityScaler: 0.1  # 10%

Alternative: Cloud Run Traffic Splitting

Wenn du Cloud Run als Backend verwendest:

# Cloud Run native Traffic Splitting
gcloud run services update-traffic my-service \
  --to-revisions=stable=90,canary=10

Eigenschaften: - ❌ GCP API Gateway: Kein Traffic Splitting - ✅ Cloud Load Balancer: Weighted Backends - ✅ Cloud Run: Native Traffic Splitting - ⚠️ Workaround benötigt zusätzliche GCP-Komponenten

Empfehlung: Für Traffic Splitting auf GCP, verwende: 1. Cloud Run (wenn serverless Backend) 2. Cloud Load Balancer + Compute Engine/GKE (wenn VM/Container Backend) 3. Alternative: Istio auf GKE (volle Traffic Management Kontrolle)


Häufige Anwendungsfälle

1. Canary Deployment (Schrittweiser Rollout)

Strategie: Neue Version schrittweise ausrollen (5% → 25% → 50% → 100%)

Phase 1: 5% Canary

traffic_split:
  enabled: true
  targets:
    - name: current
      weight: 95
      upstream: {host: api-v1, port: 8080}
    - name: new
      weight: 5
      upstream: {host: api-v2, port: 8080}

Phase 2: 25% Canary (wenn Phase 1 erfolgreich)

targets:
  - name: current
    weight: 75
  - name: new
    weight: 25

Phase 3: 50/50 Split

targets:
  - name: current
    weight: 50
  - name: new
    weight: 50

Phase 4: 100% Neues Backend

targets:
  - name: current
    weight: 0
  - name: new
    weight: 100

Rollback: Gewichte wieder auf current: 100, new: 0 setzen

2. A/B Testing

Strategie: Zwei Versionen parallel testen und Metriken vergleichen

traffic_split:
  enabled: true
  targets:
    - name: version_a
      weight: 50
      upstream: {host: api-v2-a, port: 8080}
      description: "Existing recommendation algorithm"
    - name: version_b
      weight: 50
      upstream: {host: api-v2-b, port: 8080}
      description: "New ML-based recommendation"

Metriken sammeln: - Conversion Rate - Click-Through Rate (CTR) - Response Time - Error Rate

Auswertung:

# Prometheus Queries
rate(http_requests_total{version="a"}[5m])
rate(http_requests_total{version="b"}[5m])

3. Blue/Green Deployment

Strategie: Sofortiges Switching zwischen zwei Versionen

Blue aktiv, Green standby:

traffic_split:
  enabled: true
  targets:
    - name: blue
      weight: 100
      upstream: {host: api-blue, port: 8080}
    - name: green
      weight: 0
      upstream: {host: api-green, port: 8080}

Instant Switch zu Green:

targets:
  - name: blue
    weight: 0
  - name: green
    weight: 100

Rollback: Instant Switch zurück zu Blue

4. Feature Flags via Headers

Strategie: Features via HTTP-Header freischalten

traffic_split:
  enabled: true
  targets:
    - name: stable
      weight: 100
      upstream: {host: api-stable, port: 8080}
    - name: experimental
      weight: 0
      upstream: {host: api-experimental, port: 8080}
  routing_rules:
    header_rules:
      - header_name: "X-Feature-Flag"
        header_value: "new-checkout"
        target_name: "experimental"
  fallback_target: "stable"

Nutzung:

# Standard-Nutzer → Stable
curl http://api.example.com/checkout

# Beta-Tester → Experimental
curl -H "X-Feature-Flag: new-checkout" http://api.example.com/checkout

5. User Segmentation (Premium/Free)

Strategie: Verschiedene Nutzergruppen auf verschiedene Backends routen

traffic_split:
  enabled: true
  targets:
    - name: free_tier
      weight: 80
      upstream: {host: api-free, port: 8080}
    - name: premium_tier
      weight: 20
      upstream: {host: api-premium, port: 8080}
  routing_rules:
    cookie_rules:
      - cookie_name: "user_tier"
        cookie_value: "premium"
        target_name: "premium_tier"
    header_rules:
      - header_name: "X-Subscription"
        header_value: "premium"
        target_name: "premium_tier"
  fallback_target: "free_tier"

6. Multi-Stage Rollout (3 Versionen gleichzeitig)

Strategie: Stable, Beta und Canary gleichzeitig laufen lassen

traffic_split:
  enabled: true
  targets:
    - name: stable
      weight: 70
      upstream: {host: api-stable, port: 8080}
    - name: beta
      weight: 20
      upstream: {host: api-beta, port: 8080}
    - name: canary
      weight: 10
      upstream: {host: api-canary, port: 8080}

Best Practices

1. Gewichte schrittweise erhöhen

Schlecht: Sofort von 0% auf 100%

# Riskant: Neue Version erhält sofort 100% Traffic
targets:
  - {name: old, weight: 0}
  - {name: new, weight: 100}

Gut: Schrittweise erhöhen mit Monitoring

# Phase 1: 5% Canary
targets:
  - {name: old, weight: 95}
  - {name: new, weight: 5}

# Phase 2 (nach 24h Monitoring): 25%
# Phase 3 (nach weiteren 24h): 50%
# Phase 4 (nach weiteren 24h): 100%

2. Immer Monitoring einrichten

Überwache folgende Metriken pro Traffic Split Target:

# Prometheus Metriken
- http_requests_total{target="stable"}
- http_requests_total{target="canary"}
- http_request_duration_seconds{target="stable"}
- http_request_duration_seconds{target="canary"}
- http_errors_total{target="stable"}
- http_errors_total{target="canary"}

3. Fallback-Target definieren

Immer einen Fallback für Header/Cookie-Routing:

traffic_split:
  enabled: true
  targets: [...]
  routing_rules: [...]
  fallback_target: "stable"  # ✅ Wichtig!

4. Session Stickiness beachten

⚠️ Problem: Nutzer wechseln zwischen Backends

# Schlecht: Nutzer kann zwischen stable/canary springen
# → Schlechte User Experience
traffic_split:
  enabled: true
  targets:
    - {name: stable, weight: 50}
    - {name: canary, weight: 50}

Lösung: Session Cookies verwenden

# Nutzer bleiben auf demselben Backend
routing_rules:
  cookie_rules:
    - cookie_name: "backend_version"
      cookie_value: "canary"
      target_name: "canary"

5. Rollback-Plan bereithalten

Immer einen schnellen Rollback-Mechanismus:

# Rollback via CLI
gal generate -f gateway-rollback.yaml -o envoy.yaml
envoy -c envoy.yaml --hot-restart

# Oder: Gewichte dynamisch anpassen (APISIX/Kong)
curl -X PATCH http://apisix-admin:9080/apisix/admin/routes/1 \
  -d '{"plugins": {"traffic-split": {"rules": [...]}}}'

6. Dokumentiere Target-Versionen

Klare Beschreibungen für jedes Target:

targets:
  - name: v1_2_5
    weight: 90
    upstream: {host: api-v1-2-5, port: 8080}
    description: "Stable version 1.2.5 (2024-01-15)"
  - name: v1_3_0_rc1
    weight: 10
    upstream: {host: api-v1-3-0-rc1, port: 8080}
    description: "Release Candidate 1.3.0-rc1 (2024-01-20)"

7. Rate Limiting pro Target

Verhindere, dass Canary überlastet wird:

routes:
  - path_prefix: /api
    traffic_split: [...]
    rate_limit:
      enabled: true
      requests_per_second: 1000  # Limit für gesamten Endpunkt

Traffic Splitting Testen

1. Unit Tests (Lokale Entwicklung)

Teste Config-Validierung:

from gal.config import TrafficSplitConfig, SplitTarget, UpstreamTarget

def test_weight_sum_validation():
    target1 = SplitTarget(name="stable", weight=90, ...)
    target2 = SplitTarget(name="canary", weight=20, ...)  # Summe = 110

    with pytest.raises(ValueError, match="must sum to 100"):
        TrafficSplitConfig(enabled=True, targets=[target1, target2])

2. Integration Tests (Provider Output)

Teste generierte Konfiguration:

def test_envoy_weighted_clusters():
    config = Config.from_yaml("traffic-split-example.yaml")
    provider = EnvoyProvider()
    output = provider.generate(config)

    assert "weighted_clusters:" in output
    assert "weight: 90" in output
    assert "weight: 10" in output

3. Manuelle Tests (Browser/cURL)

Weight-based Testing:

# 100 Requests senden, Verteilung prüfen
for i in {1..100}; do
  curl -s http://localhost:8080/api | grep -o "Backend: [a-z]*"
done | sort | uniq -c

# Erwartete Ausgabe (90/10 Split):
# 90 Backend: stable
# 10 Backend: canary

Header-based Testing:

# Normal → Production
curl -v http://localhost:8080/api | grep "Backend:"
# Output: Backend: production

# Mit Beta-Header → Beta
curl -v -H "X-Version: beta" http://localhost:8080/api | grep "Backend:"
# Output: Backend: beta

Cookie-based Testing:

# Mit Canary-Cookie → Canary
curl -v --cookie "canary_user=true" http://localhost:8080/api | grep "Backend:"
# Output: Backend: canary

4. Load Testing (k6, Apache Bench)

k6 Script für Traffic Split Testing:

import http from 'k6/http';
import { check } from 'k6';

export let options = {
  vus: 100,
  duration: '30s',
};

export default function() {
  let res = http.get('http://localhost:8080/api');
  check(res, {
    'is status 200': (r) => r.status === 200,
    'backend is stable or canary': (r) =>
      r.body.includes('Backend: stable') ||
      r.body.includes('Backend: canary'),
  });
}

Ausführen:

k6 run traffic-split-test.js

# Ergebnis analysieren:
# http_req_duration..........: avg=10ms min=5ms max=50ms
# Backend stable: ~90% der Requests
# Backend canary: ~10% der Requests


Troubleshooting

Problem 1: Gewichte summieren sich nicht zu 100

Fehlermeldung:

ValueError: Total weight must sum to 100 for weight-based routing, got 110

Lösung:

# ❌ Falsch: 90 + 20 = 110
targets:
  - {name: stable, weight: 90}
  - {name: canary, weight: 20}

# ✅ Korrekt: 90 + 10 = 100
targets:
  - {name: stable, weight: 90}
  - {name: canary, weight: 10}

Problem 2: Fallback Target existiert nicht

Fehlermeldung:

ValueError: Fallback target 'production' not found in targets

Lösung:

# ❌ Falsch: Target "production" nicht in Liste
targets:
  - {name: stable, weight: 100}
  - {name: canary, weight: 0}
fallback_target: "production"  # Existiert nicht!

# ✅ Korrekt: Fallback muss in targets sein
targets:
  - {name: production, weight: 100}
  - {name: canary, weight: 0}
fallback_target: "production"

Problem 3: Alle Requests gehen zu einem Backend

Symptom: Trotz 90/10 Split gehen 100% zu einem Backend

Mögliche Ursachen: 1. Provider nicht neu gestartet

# Lösung: Provider neu laden
docker restart envoy
nginx -s reload

  1. Falsche Cluster-Namen (Envoy)

    # Check Envoy Admin API
    curl http://localhost:9901/clusters | grep api
    
    # Erwartet: api_stable_cluster, api_canary_cluster
    

  2. Kong Upstream nicht aktiv

    # Check Kong Admin API
    curl http://localhost:8001/upstreams/api_route0_upstream/targets
    
    # Erwartet: Beide Targets mit korrekten Gewichten
    

Problem 4: Header-Routing funktioniert nicht

Symptom: Header wird ignoriert, fallback_target wird verwendet

Debug-Schritte:

  1. Header-Namen Case-Sensitivity prüfen

    # ❌ Falsch: Header-Namen sind case-sensitive
    header_rules:
      - header_name: "x-version"  # Wird als "X-Version" gesendet!
    
    # ✅ Korrekt: Exakte Schreibweise verwenden
    header_rules:
      - header_name: "X-Version"
    

  2. Provider-spezifische Variable prüfen

    # Nginx: Header "X-Version" → Variable "$http_x_version"
    if ($http_x_version = 'beta') {
        proxy_pass http://api-beta:8080;
    }
    

  3. APISIX vars prüfen

    // APISIX: "X-Version" → "http_x_version"
    {
      "vars": [["http_x_version", "==", "beta"]]
    }
    

Problem 5: Traffic Split zu langsam

Symptom: Response Time deutlich höher mit Traffic Splitting

Mögliche Ursachen: 1. Zu viele if-Statements (Nginx)

# Problematisch: 10+ if-Statements
# Lösung: Nginx Plus verwenden oder zu APISIX wechseln

  1. Upstream Health Checks fehlen

    # Lösung: Health Checks hinzufügen
    upstream:
      health_check:
        active:
          enabled: true
          interval: "10s"
    

  2. Connection Pooling deaktiviert

    # Lösung: Connection Pooling aktivieren
    upstream:
      load_balancer:
        algorithm: round_robin
        sticky_sessions: true  # Reduziert Connection Overhead
    


Weiterführende Ressourcen

Provider-Dokumentation

Deployment Patterns

GAL Beispiele


Version: 1.4.0 Feature: A/B Testing & Traffic Splitting Letzte Aktualisierung: 2025-01-22