Нагрузочное тестирование и стресс
Нагрузочное тестирование и стресс
1) Зачем это нужно
Цели:- Подтвердить емкость (сколько RPS/конкурентных сессий выдержит система при заданном SLO).
- Найти бутылочные горлышки (CPU/IO/БД/сети/блокировки/пулы).
- Настроить перформанс-бюджеты и «гейты» в CI/CD.
- Снизить риск релизов (регрессии p95/p99, рост ошибок при пике).
- Спланировать емкость/стоимость (скейл-аут и резервы).
2) Типы перф-тестов
Load (рабочая нагрузка): реалистичный трафик близкий к пикам; валидация SLO.
Stress (стресс): рост до/выше предела → поведение при деградации, где ломается.
Spike (импульс): быстрый скачок нагрузки → эластичность/автоскейл.
Soak / Endurance (продолжительный): часы/сутки → утечки, фрагментация, дрейф latency.
Capacity/Scalability: как меняется throughput/latency при scale-out; закон Амдала/Густафсона.
Smoke perf: короткий «дымовой» прогон на каждом релизе (перформанс-санити).
3) Модели генерации трафика
Закрытая модель (fixed VUs/concurrency): `N` пользователей, каждый делает запросы → очередь в клиенте. Риск скрыть перегрузку.
Открытая модель (arrival rate): поток заявок с интенсивностью λ (req/s), как в реальной жизни. Корректнее для публичных API.
Закон Литтла: `L = λ × W`.
Для пула/сервиса: минимальный параллелизм ≈ `λ × W` (добавьте 20–50% запаса).
Где `λ` — throughput, `W` — среднее время обслуживания.
4) Профили нагрузки и сценарии
User journey mix: доли сценариев (login, browse, deposit, checkout…).
Think-time: паузы пользователя (распределения: экспоненциальное/логнормальное).
Data profile: размер ответов, payload, вариативность параметров.
Корреляция: связывайте шаги (куки/токены/ID) как в реальном флоу.
Холод/теплый/горячий кеш: отдельные прогоны.
Read vs Write: баланс чтений/записей, идемпотентность для ретраев.
Мульти-регион: RTT, распределение по POP/ASN.
5) Среда тестирования
Изоляция: стенд близок к проду по топологии/настройкам (но не «бьем» прод).
Данные: маскирование PII, объемы, индексы как в проде.
Генераторы нагрузки: не упираются в CPU/сеть; распределенные раннеры, синхронизация времени.
Наблюдаемость: метрики/трейсы/логи, синтетика на периметре, экспорт профилей CPU/heap.
6) Метрики и SLI
Throughput: RPS/транзакции в сек.
Latency: p50/p95/p99, TTFB, server time vs network.
Errors: доля 5xx/4xx/доменных ошибок.
Saturation: CPU, load avg, GC, дисковые IOps/латентность, network, pool wait.
Бизнес-SLI: успех депозита ≤ 5s, подтверждение заказа ≤ 2s.
Пороговые значения берите из SLO (например, «99.95% ≤ 300 ms»), мониторьте burn-rate во время прогона.
7) Поиск узких мест (методика)
1. Стабильно прогрейте систему на 60–80% целевой нагрузки.
2. Увеличивайте ступенями (ramp) → фиксируйте где растет p95/p99 и error-rate.
- очередями в пулах (DB/HTTP),
- ростом WAIT/локов (БД),
- GC-паузы/heap,
- сетевые retransmits/packet loss,
- дисковая латентность/кэш-промахи.
- 4. Локализуйте: бинарный поиск по пути запроса, профилировщики (CPU/alloc/lock-profile).
- 5. Фиксируйте «бутылку» → тюнинг → повтор прогона.
8) Поведение под стрессом
Graceful degradation: лимиты, circuit-breakers, очереди с backpressure, режим «принято в обработку».
Ретраи: максимум 1, только идемпотентные; джиттер; бюджет ретраев ≤ 10% от RPS.
Fail-open/Fail-closed: для не-критичных зависимостей допускайте fail-open (кеш/заглушки).
Cascading failure: изоляция пулов/квоты (bulkhead), быстрые таймауты, «плавное» отключение функций (feature flags).
9) Инструменты (выбор под задачу)
k6 (JavaScript, открытая/open-model, быстрый, удобен в CI).
JMeter (богатый экосистемой, GUI/CLI, плагины, но тяжелее).
Gatling (Scala DSL, высокая производительность).
Locust (Python, гибкость сценариев).
Vegeta/hey/wrk (микро-бенчи и быстрая проверка).
Правило: один «основной» инструмент + легкий CLI для smoke-перф в PR.
10) Примеры (сниппеты)
10.1 k6 (открытая модель с arrival rate)
js import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
scenarios: {
open_model: {
executor: 'ramping-arrival-rate',
startRate: 200, timeUnit: '1s',
preAllocatedVUs: 200, maxVUs: 2000,
stages: [
{ target: 500, duration: '5m' }, // до 500 rps
{ target: 800, duration: '5m' }, // стресс
{ target: 0, duration: '1m' }
]
}
},
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<800'],
http_req_failed: ['rate<0.005'],
},
};
export default function () {
const res = http.get(`${__ENV.BASE_URL}/api/catalog?limit=20`);
sleep(Math.random() 2); // think-time
}
10.2 JMeter (идея профиля)
Thread Group + Stepping Thread или Concurrency Thread (open-like).
HTTP Request Defaults, Cookie Manager, CSV Data Set.
Backend Listener → InfluxDB/Grafana; Assertions по времени/коду.
10.3 Locust (Python)
python from locust import HttpUser, task, between class WebUser(HttpUser):
wait_time = between(0.2, 2.0)
@task(5)
def browse(self): self.client.get("/api/catalog?limit=20")
@task(1)
def buy(self): self.client.post("/api/checkout", json={"sku":"A1","qty":1})
11) Данные, корреляция, подготовка
Seed-данные: каталоги, пользователи, балансы, токены — как в проде.
Маскирование/анонимизация PII; генерация синтетики поверх реальных распределений.
Корреляция: извлекайте ID/токены из ответов (RegExp/JSONPath) и используйте в последующих шагах.
12) Наблюдаемость во время прогонов
RED-дашборды (Rate, Errors, Duration) по маршрутам.
Exemplars: переход из метрик к трассам (trace_id).
Логи ошибок: сэмплинг + агрегация, дубликаты/идемпотентность.
Системные: CPU/GC/heap, диски/сеть, pool wait.
БД: топ-запросы, блокировки, индекс-сканы, bloat.
13) Автоматизация и перформанс-гейты
CI: короткие прогоны на merge (например, k6 2–3 минуты) с порогами.
Nightly/Weekly: длинные soak/stress в отдельной среде; отчеты и тренды.
Канареечные релизы: анализ SLO (error-rate, p95) как «гейт» промоушена.
Регрессии: baseline vs текущий билд; алерты при ухудшении > X%.
14) Планирование емкости и стоимость
Кривые throughput→latency: определите knee point (колено) — после него p99 растет резко.
Скейл-аут: измеряйте эффективность масштабирования (дельта RPS / дельта узлов).
Стоимость: «RPS на $/час», резерв на пиковые события + DR-резерв.
15) Анти-паттерны
Бить в прод без контроля или тестировать в «пустой» среде, не похожей на прод.
Закрытая модель с фиксированными VU, скрывающая перегрузку.
Отсутствие think-time/данных → нереалистичные хиты кеша или наоборот — шторма к исходникам.
Один сценарий «/ping» вместо пользовательских флоу.
Отсутствие наблюдаемости: «видим только RPS и среднюю задержку».
Бесконтрольные ретраи → само-DDoS.
Смешивание теста и оптимизаций без фиксации гипотез/изменений.
16) Чек-лист (0–30 дней)
0–7 дней
Определите SLI/SLO и целевые профили трафика (mix, think-time, данные).
Выберите инструмент (k6/JMeter/Locust), поднимите дашборды RED.
Подготовьте стенд и seed-данные, отключите сторонние лимиты/каптчи.
8–20 дней
Постройте сценарии: open-model (arrival rate), холод/теплый/горячий кеш.
Запустите load → stress → spike; зафиксируйте knee point и узкие места.
Внедрите перформанс-гейты в CI (микро-прогон).
21–30 дней
Soak-тест 4–24 ч: утечки/дрейф GC, стабилизация.
Документируйте пределы, план емкости, иллюстрации «RPS→p95/ошибки».
Подготовьте runbook «как увеличивать лимиты/скейл» и «как деградировать».
17) Метрики зрелости
Есть реалистичные профили (mix, think-time, данные), покрывающие ≥ 80% трафика.
RED-дашборды + трассировка подключены для всех тестов.
Перформанс-гейты блокируют релизы при регрессии p95/ошибок.
Емкость и knee point документированы по ключевым сервисам.
Ежемесячные soak/stress-прогоны и отчеты по динамике.
Устойчивость к «spike» подтверждена автоскейлом и отсутствием cascade-fail.
18) Заключение
Нагрузочное тестирование — это регулярная инженерная практика, а не разовый «замер». Моделируйте реальных пользователей (open-model), мерьте то, что отражает опыт клиента (SLI/SLO), держите наблюдаемость и «гейты» в CI/CD, проводите stress/spike/soak-прогоны и фиксируйте knee point. Тогда пиковые события и «черные лебеди» превращаются в управляемые сценарии, а производительность — в предсказуемый и измеримый параметр вашей платформы.