TL;DR

  • Нагрузочное тестирование: Измерение производительности системы под ожидаемым трафиком
  • Цель: Проверить что приложение выдерживает нормальную и пиковую нагрузку
  • Ключевые метрики: Время ответа (p95), пропускная способность, процент ошибок
  • Популярные инструменты: k6 (современный), JMeter (GUI), Gatling (Scala)
  • Лучшая практика: Тестируй в production-like окружении с реалистичными данными
  • Когда запускать: Перед релизами, после крупных изменений, регулярно в CI/CD

Время чтения: 12 минут

Нагрузочное тестирование гарантирует что приложение справится с реальным трафиком. Без него ты узнаёшь о проблемах производительности от злых пользователей — или хуже, в критический момент для бизнеса.

Что такое Нагрузочное Тестирование?

Нагрузочное тестирование измеряет производительность системы под ожидаемым пользовательским трафиком. Оно симулирует много одновременных пользователей делающих запросы чтобы проверить что приложение выдерживает нагрузку без замедления или отказов.

Нормальный трафик:   100 users/мин → Время ответа: 200ms ✓
Пиковый трафик:      500 users/мин → Время ответа: 350ms ✓
Сверх мощности:     1000 users/мин → Время ответа: 5000ms ✗

Нагрузочное тестирование отвечает на вопрос: “Выдержит ли система ожидаемый трафик?”

Зачем Нужно Нагрузочное Тестирование

1. Проблемы Производительности Дорого Стоят

Медленные приложения стоят денег:

Время ответаВлияние
До 1 секундыПользователи вовлечены
1-3 секунды40% уходят
3+ секунд70%+ уходят
10+ секундПользователи редко возвращаются

Каждые 100мс задержки могут снизить конверсию на 1%.

2. Отказы в Production Хуже

Обнаружение проблем в production означает:

  • Потерю дохода во время простоя
  • Ущерб репутации
  • Экстренные фиксы под давлением
  • Потенциальную потерю данных

Нагрузочное тестирование находит проблемы раньше пользователей.

3. Трафик Непредсказуем

Реальные паттерны трафика меняются:

Понедельник 9:00: Пик от рабочих часов
Пятница 17:00:    Падение когда уходят с работы
Чёрная Пятница:   10x обычного трафика
Вирусный момент:  100x обычного трафика (если повезёт)

Нагрузочное тестирование готовит к пикам.

Типы Performance Тестирования

Load Testing (Нагрузочное)

Тестирует ожидаемые уровни трафика:

// k6 load test - ожидаемый трафик
export const options = {
  stages: [
    { duration: '5m', target: 100 },  // Разгон
    { duration: '10m', target: 100 }, // Устойчивое состояние
    { duration: '5m', target: 0 },    // Спад
  ],
};

Цель: Проверить нормальную работу.

Stress Testing (Стресс)

Давит за пределы ожидаемого:

// k6 stress test - найти точку отказа
export const options = {
  stages: [
    { duration: '2m', target: 100 },
    { duration: '5m', target: 200 },
    { duration: '5m', target: 400 },
    { duration: '5m', target: 800 },  // Сверх нормы
    { duration: '2m', target: 0 },
  ],
};

Цель: Найти максимальную мощность и точки отказа.

Spike Testing (Пиковое)

Тестирует внезапные всплески трафика:

// k6 spike test - внезапный всплеск
export const options = {
  stages: [
    { duration: '1m', target: 50 },
    { duration: '30s', target: 500 }, // Внезапный пик
    { duration: '2m', target: 500 },
    { duration: '30s', target: 50 },  // Возврат
  ],
};

Цель: Проверить что система справляется с резкими изменениями.

Soak Testing (Длительное)

Тестирует производительность за длительный период:

// k6 soak test - длительное тестирование
export const options = {
  stages: [
    { duration: '5m', target: 100 },
    { duration: '8h', target: 100 },  // 8 часов
    { duration: '5m', target: 0 },
  ],
};

Цель: Найти утечки памяти и деградацию со временем.

Ключевые Метрики

Время Ответа

Сколько времени занимают запросы:

p50 (медиана):  200ms - Половина запросов быстрее
p95:            500ms - 95% запросов быстрее
p99:           1200ms - 99% запросов быстрее
Max:           5000ms - Самый медленный запрос

Фокусируйся на p95/p99 — они показывают худший пользовательский опыт.

Пропускная Способность

Обработанных запросов за единицу времени:

Запросов/секунду:    150 req/s
Транзакций/секунду:  30 tx/s
Передача данных:     15 MB/s

Выше пропускная способность = больше мощности.

Процент Ошибок

Процент неудачных запросов:

Успешных запросов: 9,850
Неудачных:           150
Процент ошибок:    1.5% ← Слишком много для production

Цель: Менее 1% ошибок, идеально менее 0.1%.

Использование Ресурсов

Серверные метрики:

CPU:       75% среднее, 95% пик
Память:    4GB / 8GB (50%)
Disk I/O:  200 IOPS
Сеть:      500 Mbps

Следи за узкими местами приближающимися к лимитам.

Первый Нагрузочный Тест

k6 (JavaScript)

// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 50,           // 50 виртуальных пользователей
  duration: '5m',    // Работать 5 минут
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% под 500ms
    http_req_failed: ['rate<0.01'],   // Менее 1% ошибок
  },
};

export default function () {
  // Тест главной страницы
  const homeResponse = http.get('https://example.com/');
  check(homeResponse, {
    'homepage status is 200': (r) => r.status === 200,
    'homepage loads fast': (r) => r.timings.duration < 500,
  });

  // Симуляция времени на размышление
  sleep(1);

  // Тест API endpoint
  const apiResponse = http.get('https://example.com/api/products');
  check(apiResponse, {
    'api status is 200': (r) => r.status === 200,
    'api returns data': (r) => JSON.parse(r.body).length > 0,
  });

  sleep(2);
}

Запуск: k6 run load-test.js

JMeter

JMeter использует XML конфигурацию, обычно созданную через GUI:

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan>
  <hashTree>
    <ThreadGroup>
      <stringProp name="ThreadGroup.num_threads">50</stringProp>
      <stringProp name="ThreadGroup.ramp_time">30</stringProp>
      <stringProp name="ThreadGroup.duration">300</stringProp>
      <HTTPSamplerProxy>
        <stringProp name="HTTPSampler.domain">example.com</stringProp>
        <stringProp name="HTTPSampler.path">/api/products</stringProp>
        <stringProp name="HTTPSampler.method">GET</stringProp>
      </HTTPSamplerProxy>
    </ThreadGroup>
  </hashTree>
</jmeterTestPlan>

Запуск: jmeter -n -t test.jmx -l results.jtl

Locust (Python)

# locustfile.py
from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
    wait_time = between(1, 3)  # Время на размышление

    @task(3)  # Больший вес
    def view_homepage(self):
        self.client.get("/")

    @task(2)
    def view_products(self):
        self.client.get("/api/products")

    @task(1)
    def view_product_detail(self):
        self.client.get("/api/products/1")

Запуск: locust -f locustfile.py --host=https://example.com

Лучшие Практики

1. Тестируй в Production-Like Окружении

Окружение важно:

❌ Тестирование на localhost с 1GB базой
✓ Тестирование на staging с данными production-размера

Результаты localhost не предсказывают production производительность

Соответствуй:

  • Характеристики серверов
  • Размер базы данных
  • Конфигурация сети
  • Интеграции с third-party

2. Используй Реалистичные Тестовые Данные

// Плохо: Всегда одинаковый запрос
http.get('/api/users/1');

// Хорошо: Разнообразные, реалистичные запросы
const userId = Math.floor(Math.random() * 10000) + 1;
http.get(`/api/users/${userId}`);

Варьируй параметры чтобы затрагивать разные code path и поведение кэша.

3. Симулируй Реальное Поведение Пользователей

Пользователи не кликают так быстро как скрипты:

export default function () {
  http.get('/');
  sleep(2);  // Время на размышление: читает главную

  http.get('/products');
  sleep(3);  // Время на размышление: смотрит товары

  http.post('/cart', { productId: 123 });
  sleep(1);  // Быстрое действие
}

Включай реалистичные задержки между действиями.

4. Определи Чёткие Критерии Pass/Fail

Установи пороги до тестирования:

export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'],
    http_req_failed: ['rate<0.01'],
    http_reqs: ['rate>100'],  // Минимальная пропускная способность
  },
};

Тесты должны автоматически проходить или падать.

5. Тестируй Регулярно

Нагрузочное тестирование не должно быть разовым:

# GitHub Actions - еженедельный load test
on:
  schedule:
    - cron: '0 2 * * 0'  # Каждое воскресенье в 2:00

jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: k6 run tests/load-test.js

Лови регрессии до того как они попадут в production.

Сравнение Инструментов

ИнструментЯзыкЛучше дляСложность изучения
k6JavaScriptРазработчиков, CI/CDНизкая
JMeterJava/XMLQA команд, GUIСредняя
GatlingScalaВысокой производительностиСредняя
LocustPythonPython командНизкая
ArtilleryJavaScriptServerless приложенийНизкая

Выбор Инструмента

Выбери k6 если:

  • Разработчики пишут тесты
  • Нужна интеграция в CI/CD
  • Предпочитаешь код GUI

Выбери JMeter если:

  • QA команда пишет тесты
  • Нужен визуальный дизайн тестов
  • Нужна обширная экосистема плагинов

Выбери Gatling если:

  • Нужна высокая производительность
  • Scala/JVM окружение
  • Детальные HTML отчёты

Интерпретация Результатов

Здоровые Результаты

✓ http_req_duration..........: avg=180ms p95=320ms p99=450ms
✓ http_req_failed............: 0.02%
✓ http_reqs..................: 15000 (250/s)
✓ vus........................: 50

Низкое время ответа, минимум ошибок, стабильная пропускная способность.

Индикаторы Проблем

✗ http_req_duration..........: avg=2500ms p95=8000ms p99=15000ms
✗ http_req_failed............: 15%
  http_reqs..................: 3000 (50/s)
  vus........................: 50

Красные флаги:

  • Высокое время ответа (особенно p95/p99)
  • Процент ошибок выше 1%
  • Пропускная способность падает под нагрузкой
  • Высокое использование ресурсов

Поиск Узких Мест

Когда тесты падают, исследуй:

  1. Код приложения — Медленные запросы, неэффективные алгоритмы
  2. База данных — Оптимизация запросов, индексы, connection pooling
  3. Инфраструктура — Лимиты CPU/памяти, пропускная способность сети
  4. Третьи стороны — Медленные внешние API, rate limits
// Добавь детальное логирование для поиска узких мест
const response = http.get('/api/users');
console.log(`DNS: ${response.timings.blocked}ms`);
console.log(`Connect: ${response.timings.connecting}ms`);
console.log(`TLS: ${response.timings.tls_handshaking}ms`);
console.log(`Waiting: ${response.timings.waiting}ms`);
console.log(`Receiving: ${response.timings.receiving}ms`);

FAQ

Что такое нагрузочное тестирование?

Нагрузочное тестирование измеряет производительность системы под ожидаемым пользовательским трафиком. Оно симулирует много одновременных пользователей делающих запросы чтобы проверить что приложение выдерживает нормальную и пиковую нагрузку без деградации производительности. В отличие от функционального тестирования которое проверяет работают ли фичи, нагрузочное тестирование проверяет работают ли фичи под реалистичным трафиком. Цель — ответить: “Выдержит ли система ожидаемое количество пользователей?”

В чём разница между load и stress тестированием?

Load тестирование симулирует ожидаемые уровни трафика для проверки нормальной работы. Stress тестирование намеренно превышает ожидаемые лимиты чтобы найти точки отказа. Думай о load тестировании как “выдержим ли нормальный трафик?” и stress тестировании как “когда мы сломаемся?” Load тестирование использует реалистичные числа пользователей; stress тестирование давит пока система не откажет. Оба ценны — load тестирование для валидации, stress для планирования мощности.

Какие метрики отслеживать при load testing?

Отслеживай ключевые метрики: Перцентили времени ответа (p50, p95, p99) показывают как пользователи воспринимают производительность — p95 значит 95% запросов быстрее этого значения. Пропускная способность (запросов в секунду) показывает мощность. Процент ошибок (процент неудачных запросов) должен быть под 1%. Использование ресурсов (CPU, память, disk I/O) выявляет узкие места. Фокусируйся на p95 времени ответа как основной метрике — она представляет реальный пользовательский опыт лучше чем средние значения.

Какие инструменты используются для load testing?

Популярные инструменты нагрузочного тестирования: k6 (на JavaScript, современный, дружественный разработчикам), JMeter (Java, GUI, много плагинов), Gatling (Scala, высокая производительность), Locust (Python, легко учить). k6 идеален для разработчиков которые хотят тесты как код в CI/CD. JMeter подходит QA командам предпочитающим визуальный дизайн тестов. Выбирай основываясь на навыках команды и потребностях интеграции.

Смотрите также