Modern QA2026Масштабирование Kubernetes и тестирование производительности контейнеров
Join

Course05 Performance & Chaos Engineering

Cutting-edge · Chapter 05

Масштабирование Kubernetes и тестирование производительности контейнеров

Updated Jul 2026

Валидация автомасштабирования Kubernetes

Kubernetes Horizontal Pod Autoscaler (HPA) обещает автоматическое масштабирование на основе CPU, памяти или пользовательских метрик. Но «настроено» не означает «работает». Тестирование производительности должно валидировать, что автомасштабирование ведёт себя корректно при реальных условиях трафика: масштабируется вверх достаточно быстро для поглощения всплесков трафика и масштабируется вниз корректно, не нарушая активные соединения.

Тест k6 для валидации HPA

// k6-container-scaling-test.js
// Verify Kubernetes HPA responds correctly to traffic spikes
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend } from 'k6/metrics';

const scalingLatency = new Trend('scaling_response_time', true);

export const options = {
  scenarios: {
    spike: {
      executor: 'ramping-arrival-rate',
      startRate: 10,
      timeUnit: '1s',
      preAllocatedVUs: 50,
      maxVUs: 500,
      stages: [
        { duration: '1m', target: 10 },    // baseline
        { duration: '30s', target: 200 },   // sudden spike
        { duration: '5m', target: 200 },    // sustain spike (HPA should scale)
        { duration: '30s', target: 10 },    // drop back
        { duration: '5m', target: 10 },     // verify scale-down
      ],
    },
  },
  thresholds: {
    // Even during spike, 95th percentile should stay under 2s
    // (once HPA has scaled, which may take 1-2 minutes)
    http_req_duration: ['p(95)<2000'],
    http_req_failed: ['rate<0.05'],
  },
};

export default function () {
  const res = http.get('https://app.example.com/api/heavy-computation');
  scalingLatency.add(res.timings.duration);

  check(res, {
    'status is 200': (r) => r.status === 200,
    'no 503 (service unavailable)': (r) => r.status !== 503,
  });
}

Что мониторить во время теста

Пока k6 работает, мониторьте кластер Kubernetes в параллельном терминале или на дашборде:

# Watch pod count change in real-time
kubectl get pods -l app=my-service -w

# Watch HPA status
kubectl get hpa my-service-hpa -w

# Check HPA events for scaling decisions
kubectl describe hpa my-service-hpa

Ожидаемая хронология

T+0:00  - 10 req/s, 3 pods (baseline)
T+1:00  - Spike to 200 req/s, latency increases immediately
T+1:30  - HPA detects CPU > target, begins scaling
T+2:00  - New pods scheduled, pulling images
T+2:30  - New pods running, latency begins to decrease
T+3:00  - Full scale-up complete (e.g., 15 pods), latency normalized
T+6:30  - Traffic drops to 10 req/s
T+7:00  - HPA begins scale-down (cooldown period)
T+11:30 - Scale-down complete, back to 3 pods

Критический вопрос: Что происходит с пользователями в период T+1:00 — T+3:00 (разрыв масштабирования)? Именно здесь вы обнаружите, достаточна ли ваша конфигурация HPA.

Конфигурация HPA для производительности

Базовый HPA на основе CPU

# hpa-cpu-based.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: checkout-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: checkout-service
  minReplicas: 3
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60   # scale up when avg CPU > 60%
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30   # react to spikes quickly
      policies:
        - type: Percent
          value: 100      # can double pod count per scaling event
          periodSeconds: 60
        - type: Pods
          value: 5         # or add 5 pods, whichever is larger
          periodSeconds: 60
      selectPolicy: Max
    scaleDown:
      stabilizationWindowSeconds: 300  # wait 5 min before scaling down
      policies:
        - type: Percent
          value: 10       # remove at most 10% of pods per interval
          periodSeconds: 60

HPA на пользовательских метриках (запросы в секунду)

HPA на основе CPU часто слишком медленный для масштабирования, управляемого трафиком. Пользовательские метрики на основе частоты запросов могут быть более отзывчивыми:

# hpa-custom-metrics.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: checkout-hpa-custom
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: checkout-service
  minReplicas: 3
  maxReplicas: 50
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: 100   # target 100 req/s per pod
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Матрица решений по тестированию производительности архитектур

Разные архитектуры имеют разные проблемы производительности. Используйте эту матрицу для выбора правильной стратегии тестирования:

Архитектура Ключевая проблема Основной инструмент Ключевая метрика
Монолит Исчерпание пула потоков k6 / JMeter Одновременные соединения
Микросервисы Межсервисная задержка, каскадные отказы k6 + распределённая трассировка Сквозная задержка p99
Serverless Холодные старты, лимиты конкурентности k6 + CloudWatch TTFB, одновременные выполнения
Edge/CDN Доля попаданий в кеш, нагрузка на origin k6 из нескольких регионов % попаданий в кеш, req/s на origin
На базе LLM Пропускная способность токенов, лимиты запросов k6 с пользовательскими метриками TPS, TTFT, срабатывания лимитов
Событийная Глубина очереди, отставание потребителя k6 + метрики очередей Отставание потребителя, задержка обработки

Тестирование каскадных отказов в микросервисах

В микросервисной архитектуре медленный нижестоящий сервис может вызвать каскадные отказы вышестоящих. Тестируйте этот сценарий явно:

// k6-cascading-failure-test.js
// Test: What happens when the payment service is slow?
import http from 'k6/http';
import { check } from 'k6';
import { Trend, Rate } from 'k6/metrics';

const orderLatency = new Trend('order_creation_latency', true);
const cascadeErrorRate = new Rate('cascade_errors');

export const options = {
  scenarios: {
    normal_traffic: {
      executor: 'constant-arrival-rate',
      rate: 50,
      timeUnit: '1s',
      duration: '10m',
      preAllocatedVUs: 50,
      maxVUs: 200,
    },
  },
  thresholds: {
    order_creation_latency: ['p(95)<5000'],  // total order flow under 5s
    cascade_errors: ['rate<0.1'],             // under 10% cascade errors
  },
};

export default function () {
  // This test runs against the order service while separately
  // injecting latency into the payment service (via Litmus/Chaos Mesh)
  const res = http.post('https://staging.example.com/api/orders',
    JSON.stringify({
      items: [{ sku: "TEST-1", qty: 1 }],
      payment: { method: "card", token: "tok_test" },
    }),
    { headers: { 'Content-Type': 'application/json' }, timeout: '30s' }
  );

  orderLatency.add(res.timings.duration);

  check(res, {
    'order created or gracefully degraded': (r) =>
      r.status === 201 || r.status === 202 || r.status === 503,
    'no 500 internal errors': (r) => r.status !== 500,
  });

  // A 503 with a retry-after header is acceptable (circuit breaker open)
  // A 500 is a cascading failure bug
  cascadeErrorRate.add(res.status === 500);
}

Запускайте этот тест k6 одновременно с экспериментом Litmus по внедрению сетевой задержки в сервис платежей для валидации корректной работы circuit breaker, таймаутов и логики отката.

Ресурсные лимиты и производительность

Ресурсные запросы и лимиты Kubernetes напрямую влияют на производительность. Недостаточно обеспеченные ресурсами контейнеры тротлятся в самый неподходящий момент:

# resource-config-for-performance.yaml
resources:
  requests:
    cpu: 500m        # guaranteed CPU allocation
    memory: 512Mi    # guaranteed memory allocation
  limits:
    cpu: 2000m       # burst capacity (4x request)
    memory: 1Gi      # hard memory limit (OOMKill if exceeded)

Тестирование производительности конфигураций ресурсов

Протестируйте ваш сервис с разными конфигурациями ресурсов для поиска оптимальных настроек:

Конфигурация CPU запрос/лимит Память запрос/лимит Результат теста
Минимальная 100m/500m 128Mi/256Mi 50 req/s, p99=2,5 с, OOMKill под нагрузкой
Консервативная 250m/1000m 256Mi/512Mi 100 req/s, p99=800 мс, стабильно
Оптимальная 500m/2000m 512Mi/1Gi 200 req/s, p99=400 мс, стабильно
Щедрая 1000m/4000m 1Gi/2Gi 200 req/s, p99=350 мс, убывающая отдача

«Оптимальная» конфигурация достигает целевой производительности без избыточного расхода ресурсов. Нагрузочное тестирование — единственный способ найти эту точку баланса.

Интеграция в CI-пайплайн: полный рабочий процесс производительности и хаос-инженерии

# .github/workflows/performance-chaos.yml
name: Performance & Chaos Pipeline
on:
  push:
    branches: [main]

jobs:
  performance-budget:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - name: Lighthouse CI
        uses: treosh/lighthouse-ci-action@v11
        with:
          configPath: ./lighthouserc.json

  load-test-staging:
    needs: performance-budget
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run k6 load tests
        uses: grafana/k6-action@v0.4.0
        with:
          filename: tests/performance/k6-load-test.js
          flags: --out json=results.json
        env:
          K6_TARGET_URL: ${{ secrets.STAGING_URL }}
      - name: Upload results
        uses: actions/upload-artifact@v4
        with:
          name: k6-results
          path: results.json

  chaos-staging:
    needs: load-test-staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Litmus
        run: |
          kubectl apply -f https://litmuschaos.github.io/litmus/litmus-operator-v3.0.0.yaml
      - name: Run chaos experiment
        run: |
          kubectl apply -f chaos/pod-delete-experiment.yaml
          kubectl apply -f chaos/network-delay-experiment.yaml
      - name: Wait for chaos completion
        run: |
          kubectl wait --for=condition=complete chaosresult/checkout-chaos \
            --timeout=600s
      - name: Verify SLOs held during chaos
        run: |
          python scripts/verify_slo_during_chaos.py \
            --prometheus-url ${{ secrets.PROMETHEUS_URL }} \
            --slo-config slo/checkout-api.yaml \
            --chaos-window 10m

Этот пайплайн гарантирует, что каждый мерж в main валидируется на производительность (Lighthouse + k6) и устойчивость (хаос Litmus). Система должна быть не только быстрой — она должна оставаться быстрой, когда что-то идёт не так.