Spike Testing: тестирование внезапных всплесков трафика
Spike test симулирует внезапный многократный рост нагрузки: реклама на ТВ, новость в СМИ, распродажа, DDoS. В отличие от стресс-теста здесь не плавное нарастание, а мгновенный скачок. Цель — убедиться, что система не падает и восстанавливается за приемлемое время.
Типичные spike сценарии
- Flash sale: нормальный трафик 200 RPS → за 30 секунд 2000 RPS
- Email-рассылка: 100k пользователей переходят по ссылке в течение 5 минут
- Новостной пик: публикация в крупном СМИ — трафик ×10 за 2 минуты
- Bot attack: внезапный DDoS с тысяч IP
k6 spike тест
// tests/spike/flash-sale.js
import http from 'k6/http'
import { check, sleep } from 'k6'
import { Rate } from 'k6/metrics'
const errorRate = new Rate('errors')
export const options = {
scenarios: {
// Базовый трафик всегда присутствует
baseline: {
executor: 'constant-vus',
vus: 20,
duration: '15m',
},
// Spike: внезапный рост
spike: {
executor: 'ramping-arrival-rate',
startRate: 20,
timeUnit: '1s',
preAllocatedVUs: 500,
maxVUs: 1000,
stages: [
{ duration: '5m', target: 20 }, // нормальная нагрузка
{ duration: '10s', target: 500 }, // резкий spike
{ duration: '2m', target: 500 }, // пик
{ duration: '10s', target: 20 }, // снятие нагрузки
{ duration: '5m', target: 20 }, // восстановление
]
}
},
thresholds: {
// Во время spike допускаем деградацию, но не падение
'http_req_duration{scenario:spike}': [
{ threshold: 'p(95)<3000', abortOnFail: false }
],
// Ошибок должно быть минимум
'errors{scenario:spike}': ['rate<0.05'], // < 5% во время spike
// После spike — полное восстановление
'http_req_duration{scenario:baseline}': ['p(95)<500']
}
}
const BASE_URL = __ENV.BASE_URL || 'https://staging.example.com'
export default function() {
// Флагманский endpoint для spike тестирования
const res = http.get(`${BASE_URL}/api/products/flash-sale`, {
timeout: '10s'
})
const success = check(res, {
'status 200': (r) => r.status === 200,
'responded in time': (r) => r.timings.duration < 3000
})
errorRate.add(!success)
sleep(Math.random() * 0.5)
}
Artillery spike сценарий
# tests/spike/artillery-spike.yml
config:
target: "{{ $processEnvironment.BASE_URL }}"
phases:
- name: "Normal traffic"
duration: 300
arrivalRate: 50
- name: "Spike onset"
duration: 30
arrivalRate: 50
rampTo: 500
- name: "Spike peak"
duration: 120
arrivalRate: 500
- name: "Spike recovery"
duration: 30
arrivalRate: 500
rampTo: 50
- name: "Post-spike normal"
duration: 300
arrivalRate: 50
ensure:
# Система должна выжить
thresholds:
- http.codes.200.percent: 95 # >= 95% успешных ответов
- http.response_time.p95: 5000 # p95 < 5 секунд
Автоскейлинг: проверка реакции
#!/bin/bash
# scripts/watch-autoscaling.sh
# Запускать параллельно со spike тестом
NAMESPACE="production"
DEPLOYMENT="api"
echo "timestamp,replicas,ready_replicas,cpu_usage"
while true; do
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
REPLICAS=$(kubectl get deployment $DEPLOYMENT -n $NAMESPACE \
-o jsonpath='{.spec.replicas}')
READY=$(kubectl get deployment $DEPLOYMENT -n $NAMESPACE \
-o jsonpath='{.status.readyReplicas}')
CPU=$(kubectl top pods -n $NAMESPACE --selector=app=$DEPLOYMENT \
--no-headers | awk '{sum+=$2} END {print sum}')
echo "$TS,$REPLICAS,$READY,${CPU}m"
sleep 15
done
Проверка очередей и circuit breakers
# Мониторинг состояния очереди во время spike
import redis
import time
r = redis.Redis()
def monitor_queues():
metrics = {}
queues = ['jobs:default', 'jobs:critical', 'jobs:email']
for queue in queues:
metrics[queue] = r.llen(queue)
return metrics
# Во время spike очереди могут накапливать задачи
# Нормально: очередь растёт во время spike, но рассасывается после
# Проблема: очередь не рассасывается — workers не успевают
Что наблюдать во время spike теста
Метрика До spike Во время spike Восстановление
─────────────────────────────────────────────────────────────────────
RPS 50 500 50
p95 latency (мс) 200 2000 200 ✓
Error rate (%) 0.1 2.0 0.1 ✓
DB active connections 10 50 10 ✓
DB queue wait (мс) 5 500 5 ✓
App replicas (k8s) 2 8 2 ✓
Memory per pod (MB) 256 512 256 ✓
Job queue depth 0 5000 0 ✓ (за 5 мин)
Если метрика не восстанавливается в течение 5 минут после снятия нагрузки — это проблема.
Типичные проблемы при spike и решения
Connection pool exhaustion: при spike все worker'ы одновременно запрашивают соединения с БД. Решение: pgBouncer transaction mode, увеличить max_connections, rate-limit на уровне приложения.
Thundering herd при кеш-промахе: spike сбрасывает кеш, все запросы идут в БД одновременно. Решение: request coalescing (один запрос к БД, остальные ждут результата), probabilistic early expiration.
Memory pressure: при spike выделяется много объектов, GC не успевает. Решение: увеличить heap limit, профилировать аллокации.
HPA реагирует слишком медленно: Kubernetes HPA по умолчанию ждёт 5 минут перед scale-up. Решение: уменьшить --horizontal-pod-autoscaler-sync-period, использовать KEDA для event-driven scaling, держать pre-warmed pods.
KEDA для мгновенного масштабирования
# keda-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: api-scaledobject
spec:
scaleTargetRef:
name: api-deployment
minReplicaCount: 3
maxReplicaCount: 50
cooldownPeriod: 300
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: http_requests_per_second
query: sum(rate(http_requests_total[30s]))
threshold: '100' # 1 pod на каждые 100 RPS
Срок выполнения
Spike тест с наблюдением за автоскейлингом и circuit breaker'ами — 1–2 рабочих дня.







