Spike Testing: тестування раптових всплесків трафіку
Spike test симулює раптовий багатократний зріст навантаження: реклама на ТВ, новина в ЗМІ, розпродаж, DDoS. На відміну від стрес-тесту, тут не плавне нарастання, а миттєвий стрибок. Мета — впевнитися, що система не падає і відновлюється за прийнятний час.
Типові spike сценарії
- Flash sale: нормальний трафік 200 RPS → 2000 RPS за 30 секунд
- 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 (ms) 200 2000 200 ✓
Error rate (%) 0.1 2.0 0.1 ✓
DB active connections 10 50 10 ✓
DB queue wait (ms) 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 робочих дні.







