Стресс-тестирование: поиск breaking point и пределов нагрузки
Ваш сайт выдерживает пиковую нагрузку? Мы помогаем найти точку отказа (breaking point) до того, как это сделают ваши пользователи. Стресс-тестирование — это нагрузочный тест, который намеренно превышает нормальные пиковые значения. Например, для интернет-магазина перед распродажей мы имитируем до 10 000 виртуальных пользователей, чтобы увидеть, при каком RPS начинаются ошибки.
Стресс-тест выявляет узкие места: БД, CPU, память, сеть. Результат — конкретные цифры: p95 latency, error rate, максимальный RPS. Это позволяет предотвратить простои и сэкономить до 40% бюджета на инфраструктуру. По данным нашей практики (100+ проектов), клиенты сокращают расходы на серверы на 30-50% после оптимизации по результатам стресс-теста.
Как определить точку отказа (breaking point)?
Мы используем ступенчатый профиль нагрузки с помощью k6 — инструмента, который потребляет в 5 раз меньше ресурсов, чем Apache JMeter, и превосходит его по производительности в 5 раз. k6 написан на Go и поддерживает скрипты на JavaScript, что делает его идеальным для CI/CD. Процесс включает четыре этапа:
- Определение baseline. Запускаем нормальную нагрузку (50–70% от ожидаемого пика) и фиксируем p95 latency, error rate, CPU/memory.
- Ступенчатое увеличение. Повышаем нагрузку шагами по 10–20% каждые 2–5 минут до появления ошибок или критической задержки.
- Поиск breaking point. Продолжаем до деградации (error rate > 5% или latency > 5× baseline).
- Восстановление. Снимаем нагрузку и измеряем время возврата системы к норме.
Ниже — пример сценария k6 для стресс-теста с постепенным нарастанием до 1600 виртуальных пользователей:
// tests/stress/breaking-point.js
import http from 'k6/http'
import { check, sleep } from 'k6'
import { Rate, Trend, Counter } from 'k6/metrics'
const errorRate = new Rate('errors')
const requestsPerSecond = new Counter('requests_per_second')
export const options = {
stages: [
{ duration: '2m', target: 50 },
{ duration: '3m', target: 50 },
{ duration: '2m', target: 100 },
{ duration: '3m', target: 100 },
{ duration: '2m', target: 200 },
{ duration: '3m', target: 200 },
{ duration: '2m', target: 400 },
{ duration: '3m', target: 400 },
{ duration: '2m', target: 800 },
{ duration: '3m', target: 800 },
{ duration: '2m', target: 1600 },
{ duration: '3m', target: 1600 },
{ duration: '5m', target: 50 },
{ duration: '3m', target: 0 },
],
thresholds: {
http_req_duration: [
{ threshold: 'p(95)<2000', abortOnFail: false },
],
errors: [
{ threshold: 'rate<0.1', abortOnFail: false }
]
}
}
const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000'
export default function() {
const responses = http.batch([
['GET', `${BASE_URL}/api/products?limit=20`],
['GET', `${BASE_URL}/api/categories`],
])
responses.forEach(r => {
check(r, { 'status 2xx': (r) => r.status >= 200 && r.status < 300 })
errorRate.add(r.status >= 400)
})
requestsPerSecond.add(2)
sleep(0.1)
}
export function handleSummary(data) {
const stages = analyzeStages(data)
return {
'stress-results.json': JSON.stringify(data, null, 2),
stdout: generateReport(stages)
}
}
function generateReport(stages) {
return `
=== STRESS TEST REPORT ===
Breaking Point Analysis:
${stages.map(s => ` VUs: ${s.vus} | p95: ${s.p95}ms | Errors: ${(s.errorRate*100).toFixed(1)}%`).join('\n')}
`
}
Почему важно фиксировать восстановление?
Надёжность системы определяется не только тем, как она держит нагрузку, но и как быстро возвращается в норму после её снятия. Медленное восстановление (больше 2 минут) — признак проблем с пулом соединений, утечки памяти или неправильной конфигурации кешей. Мы обязательно тестируем этот сценарий, чтобы гарантировать стабильность даже после аварийного пика.
Кейс из практики: недавно мы провели стресс-тест для маркетплейса. При нагрузке 500 RPS всё было стабильно, но после снятия нагрузки система восстанавливалась 4 минуты. Диагностика показала неверные настройки пула подключений к PostgreSQL. После оптимизации время восстановления сократилось до 30 секунд, а пропускная способность выросла до 1500 RPS.
Мониторинг во время теста
Параллельно со стресс-тестом мы запускаем сбор системных метрик на целевых серверах. Пример скрипта мониторинга CPU, памяти, загрузки и состояния PostgreSQL:
#!/bin/bash
# scripts/monitor-stress-test.sh
TARGET_HOST="app-server-ip"
INTERVAL=10
while true; do
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
ssh $TARGET_HOST "
echo -n '$TIMESTAMP '
echo -n 'cpu:'; top -bn1 | grep 'Cpu(s)' | awk '{print \$2}'; echo -n ' '
echo -n 'mem:'; free | grep Mem | awk '{print \$3/\$2 * 100}'; echo -n ' '
echo -n 'load:'; cat /proc/loadavg | awk '{print \$1}'
echo -n 'conns:'; ss -s | grep -o 'estab [0-9]*' | awk '{print \$2}'
"
ssh $TARGET_HOST "
PGPASSWORD=pass psql -U app -d appdb -t -c \"
SELECT 'active_queries:', count(*) FROM pg_stat_activity
WHERE state = 'active' AND query NOT LIKE '%pg_stat%';
SELECT 'long_queries:', count(*) FROM pg_stat_activity
WHERE state = 'active' AND query_start < NOW() - interval '5 seconds';
SELECT 'locks:', count(*) FROM pg_locks WHERE NOT granted;
\"
"
sleep $INTERVAL
done | tee stress-monitor.log
Как анализировать результаты с Prometheus и Grafana?
Мы отправляем метрики k6 в Prometheus через Remote Write и строим дашборды в Grafana. Пример PromQL для визуализации:
# RPS в реальном времени
rate(k6_http_reqs_total[30s])
# Error rate по времени (найти момент деградации)
rate(k6_http_req_failed_total[30s]) / rate(k6_http_reqs_total[30s])
# p95 latency в реальном времени
histogram_quantile(0.95, rate(k6_http_req_duration_seconds_bucket[30s]))
Скрипт Python для автоматического поиска breaking point:
# analyze_stress_results.py
import json
import pandas as pd
def analyze_breaking_point(results_file):
with open(results_file) as f:
data = json.load(f)
metrics = data['metrics']
analysis = {
'max_rps_before_errors': find_max_sustainable_rps(metrics),
'error_threshold_rps': find_error_threshold(metrics),
'latency_degradation_point': find_latency_degradation(metrics),
'recovery_time_seconds': find_recovery_time(metrics),
}
print("=== Breaking Point Analysis ===")
print(f"Max sustainable RPS (< 1% errors): {analysis['max_rps_before_errors']}")
print(f"Error threshold RPS: {analysis['error_threshold_rps']}")
print(f"p95 > 1s at RPS: {analysis['latency_degradation_point']}")
print(f"Recovery time after load removal: {analysis['recovery_time_seconds']}s")
if analysis['max_rps_before_errors'] < 100:
print("\n[!] LOW capacity. Consider: DB connection pooling, caching, horizontal scaling")
elif analysis['recovery_time_seconds'] > 120:
print("\n[!] SLOW recovery. Consider: circuit breakers, graceful degradation")
return analysis
Когда следует проводить стресс-тестирование?
Рекомендуем проводить стресс-тесты после каждого значимого релиза, при изменении архитектуры (например, миграция на новый хостинг или добавление кеширования), а также планово раз в квартал для мониторинга деградации производительности. Это поможет своевременно выявить проблемы с производительностью и избежать простоев.
Типичные узкие места и диагностика
| Симптом | Вероятная причина | Диагностика |
|---|---|---|
| Latency растёт, CPU низкий | Блокировки БД или медленные запросы | pg_stat_activity, slow query log |
| CPU 100%, мало ошибок | Вычислительный bottleneck | top, профилировщик приложения |
ENOMEM ошибки |
Утечка памяти или OOM | free -m, /proc/meminfo |
| Connection refused | Исчерпан pool соединений | pgBouncer stats, netstat |
| 502 Bad Gateway | Worker processes перегружены | Nginx error log, worker_processes |
Сравнение инструментов для стресс-тестирования
| Инструмент | Ресурсы | Сценарии | Интеграция |
|---|---|---|---|
| k6 | 5x меньше, чем JMeter | JavaScript, Go-like | Prometheus, Grafana, Datadog |
| Apache JMeter | Тяжёлый | GUI, XML | Плагины |
| Locust | Средний | Python | InfluxDB |
k6 выигрывает в производительности и простоте автоматизации. Мы используем его во всех проектах. Более 10 лет опыта в нагрузочном тестировании позволяют нам быстро выявлять узкие места и давать точные рекомендации.
Что входит в работу
- Документация по выявленному breaking point (RPS, latency, error rate)
- Дашборды Grafana с историей тестов и корреляцией метрик
- Рекомендации по оптимизации с приоритетами (критичные / желательные)
- Повторное тестирование после внесения изменений
- Отчёт о восстановлении системы после нагрузки
Сроки и стоимость
Стандартный стресс-тест с описанным сценарием занимает 2–3 рабочих дня. Стоимость рассчитывается индивидуально в зависимости от сложности архитектуры и количества целевых эндпоинтов. Свяжитесь с нами для точной оценки вашего проекта — мы подберём профиль нагрузки и согласуем метрики.
Получив результаты, вы сможете уверенно масштабировать сайт, избегая простоев в пиковые моменты. Наш опыт — 100+ успешных стресс-тестов для проектов разного масштаба — гарантирует объективность и прикладную пользу. Закажите стресс-тест и получите детальный отчёт с рекомендациями. Или свяжитесь с нами, чтобы обсудить ваш проект.







