Нагрузочное тестирование
Нагрузочное тестирование — проверка производительности API под нагрузкой (RPS, время ответа, потребление ресурсов). Виды: Load (ожидаемая нагрузка), Stress (до разрушения), Soak (длительная, утечки памяти), Spike (резкий скачок). Ключевые метрики: p50/p95/p99 (время ответа), RPS (пропускная способность), CPU/RAM, процент ошибок (5xx, таймауты). Инструменты: k6 (современный), JMeter (классика), Locust (Python). Сценарии: постепенное увеличение, постоянная нагрузка, пик, до разрушения. Анализ: смотреть на перцентили, не на среднее; искать узкие места (БД, сеть, приложение, кеш). В CI/CD: ночной запуск на стенде, похожем на production.
Введение: Проверка на прочность
Представьте, что вы построили мост. Архитекторы проверили чертежи. Строители проверили каждый болт и каждую сварку. Но вы не знаете, выдержит ли мост 10 машин одновременно. Или 100. Или 1000.
Нагрузочное тестирование — это проверка моста на прочность. В мире API это проверка того, как система ведёт себя под нагрузкой: сколько запросов в секунду выдерживает, как быстро отвечает, не падает ли, когда становится тяжело.
Нагрузочное тестирование (Load Testing) — это тестирование производительности системы под ожидаемой нагрузкой. Оно отвечает на вопросы: “Сколько пользователей может обслуживать API?”, “Какое время ответа?”, “Где узкое место?”.
Для системного аналитика нагрузочное тестирование — это проверка нефункциональных требований. Вы не проверяете, правильно ли API считает скидку (это модульные тесты). Вы проверяете, что API отвечает за 200 мс при 1000 запросах в секунду.
Виды нагрузочного тестирования
| Вид | Вопрос | Цель |
|---|---|---|
| Load Testing | “Выдержит ли ожидаемую нагрузку?” | Проверка соответствия требованиям |
| Stress Testing | “Когда сломается?” | Найти предел прочности |
| Soak Testing | “Не течёт ли под нагрузкой?” | Проверка утечек памяти, ресурсов |
| Spike Testing | “Переживёт ли резкий скачок?” | Проверка на внезапные всплески |
Ключевые метрики
Время отклика (Latency)
| Показатель | Что значит | Типичные цели |
|---|---|---|
| p50 (медиана) | Половина запросов быстрее этого времени | < 100 мс |
| p95 | 95% запросов быстрее | < 300 мс |
| p99 | 99% запросов быстрее | < 500 мс |
| p100 (максимум) | Самый медленный запрос | < 2000 мс |
Что важно понимать: Среднее арифметическое (mean) часто обманчиво. Медиана (p50) даёт лучшее представление о типичном пользователе.
Пропускная способность (Throughput)
| Показатель | Что значит |
|---|---|
| RPS (Requests Per Second) | Запросов в секунду |
| TPS (Transactions Per Second) | Транзакций в секунду |
Потребление ресурсов
| Ресурс | Что смотреть |
|---|---|
| CPU | Процент загрузки процессора |
| RAM | Потребление памяти |
| Сеть | Входящий/исходящий трафик |
| Диск | IOPS, чтение/запись |
| БД | Количество соединений, медленные запросы |
Процент ошибок
| Показатель | Что значит | Допустимо |
|---|---|---|
| Error Rate | Доля запросов с ошибкой (5xx) | < 0.1% |
| Timeout Rate | Доля таймаутов | 0% |
Процесс нагрузочного тестирования
Этапы
graph LR
A[Планирование] --> B[Создание сценариев]
B --> C[Запуск тестов]
C --> D[Сбор метрик]
D --> E[Анализ]
E --> F[Оптимизация]
F --> B
Что делает аналитик на каждом этапе
| Этап | Действия аналитика |
|---|---|
| Планирование | Определить цели: “API должен выдерживать 1000 RPS с p95 < 200 мс” |
| Создание сценариев | Определить, какие эндпоинты тестировать, с какими параметрами |
| Запуск | Согласовать время (не в час пик), запустить тесты |
| Сбор метрик | Получить отчёты из инструментов |
| Анализ | Понять, где узкое место |
| Оптимизация | Передать выводы разработчикам, архитекторам |
Инструменты нагрузочного тестирования
Популярные инструменты
| Инструмент | Язык сценариев | Что умеет | Популярность |
|---|---|---|---|
| JMeter | GUI / XML | Всё | Высокая |
| k6 | JavaScript | Современный, облачный | Высокая |
| Gatling | Scala / Kotlin | Мощные отчёты | Средняя |
| Locust | Python | Гибкий | Средняя |
| Yandex.Tank | YAML / Python | Интеграция с Яндекс.Облаком | Низкая (СНГ) |
Что важно для аналитика
| Аспект | Что смотреть |
|---|---|
| Отчёты | Графики, перцентили, количество ошибок |
| Настраиваемость | Можно ли задать разные типы нагрузки |
| Интеграция | Можно ли встроить в CI/CD |
| Цена | Есть ли бесплатная версия |
Сценарии нагрузки
Постепенное увеличение (Ramp-up)
Нагрузка растёт постепенно от 0 до целевого значения.
Время (сек): 0 → 60 → 120
RPS: 0 → 500 → 1000Что даёт: Позволяет увидеть, при какой нагрузке начинаются проблемы.
Постоянная нагрузка (Constant)
Фиксированное количество RPS в течение времени.
Время (сек): 0 → 300 → 600
RPS: 1000 → 1000 → 1000Что даёт: Проверка стабильности под нагрузкой.
Пиковая нагрузка (Spike)
Внезапный резкий скачок нагрузки.
Время (сек): 0 → 10 → 60
RPS: 100 → 5000 → 100Что даёт: Проверка, не падает ли система при резком скачке.
Нагрузка до разрушения (Stress)
Нагрузка увеличивается, пока система не начнёт падать.
Время (сек): 0 → 300 → ...
RPS: 100 → 200 → 400 → 800 → 1600 → (падение)Что даёт: Понимание предела прочности.
Анализ результатов
Хорошие результаты
| Показатель | Значение |
|---|---|
| p95 | < 200 мс |
| Error rate | < 0.1% |
| RPS | ≥ целевого |
| CPU | < 70% |
| RAM | < 80% |
Тревожные сигналы
| Сигнал | Что может значить |
|---|---|
| p95 резко растёт после какого-то RPS | Узкое место, очередь |
| Ошибки 5xx появляются при нагрузке | Сервер не справляется |
| Ошибки 429 (Too Many Requests) | Rate limiting сработал |
| Таймауты увеличиваются | База данных медленная |
| CPU 100% | Упираемся в процессор |
| RAM растёт бесконечно | Утечка памяти |
Типичные узкие места
| Узкое место | Признаки | Кто решает |
|---|---|---|
| База данных | Медленные запросы, высокая загрузка CPU на БД | Разработчики, DBA |
| Сеть | Высокая задержка, потери пакетов | DevOps, сетевики |
| Приложение | Высокий CPU, много потоков в WAIT | Разработчики |
| Внешние API | Таймауты, ошибки от внешнего сервиса | Команда интеграции |
| Кеш (Redis) | Высокая задержка, ошибки | Разработчики, DevOps |
Пример: Отчёт нагрузочного тестирования
Шапка
Отчёт нагрузочного тестирования
API: GET /users/{id}
Дата: 2024-01-15
Цель: 1000 RPS, p95 < 200 мс
Инструмент: k6Результаты
| Показатель | Значение | Статус |
|---|---|---|
| Максимальный RPS | 1050 | ✅ |
| p50 | 45 мс | ✅ |
| p95 | 180 мс | ✅ |
| p99 | 320 мс | ❌ (цель 300 мс) |
| Error rate | 0.05% | ✅ |
| CPU (макс) | 65% | ✅ |
| RAM (макс) | 2.1 ГБ | ✅ |
График
Время отклика (мс)
500 | *
400 | * *
300 | * * *
200 | * * * * * * * * * * * * *
100 | * * * * * * * * * * * * * * *
0 +--------------------------------
0 100 200 300 400 500 600 RPSВыводы
1. Целевая нагрузка 1000 RPS достигнута.
2. p99 превышает цель (320 мс > 300 мс) при нагрузке > 800 RPS.
3. Рекомендация: оптимизировать медленные запросы, добавить кеш.Нагрузочное тестирование в CI/CD
Где запускается
graph LR
A[Модульные тесты] --> B[Интеграционные]
B --> C[Нагрузочные]
C -->|Ночной запуск| D[Отчёт утром]
Особенности запуска
| Аспект | Как |
|---|---|
| Частота | Не на каждый коммит (долго, дорого) |
| Время | Ночью, в выходные |
| Среда | Staging, не production |
| Мониторинг | Собирать метрики с серверов, БД, кеша |
Интеграция с CI
# Пример .gitlab-ci.yml
load_test:
stage: test
script:
- k6 run load_test.js
artifacts:
reports:
load_report: load_report.json
only:
- main
when: manualРаспространённые ошибки
Ошибка 1: Тестирование на неправильных данных
Тесты используют одни и те же данные, кеш разогрет, БД не напрягается.
Решение: Использовать разные данные (параметризация).
Ошибка 2: Тестирование на неправильной среде
Среда отличается от production: меньше ресурсов, другая конфигурация.
Решение: Стенд для нагрузочного тестирования должен быть как production.
Ошибка 3: Игнорирование холодного старта
Первый запрос после запуска может быть медленным из-за инициализации.
Решение: Игнорировать первые N запросов или сделать прогревочный прогон.
Ошибка 4: Смотреть только среднее
Среднее может быть хорошим, а p99 — ужасным.
Решение: Смотреть на перцентили (p95, p99).
Ошибка 5: Тестирование одного эндпоинта
В реальности пользователи делают разные запросы.
Решение: Смешанный сценарий: 60% GET /users, 20% GET /orders, 10% POST /orders, 10% остальное.
Планирование нагрузочного тестирования
Вопросы для аналитика
| Вопрос | Зачем |
|---|---|
| “Какая ожидаемая нагрузка?” | Целевые RPS |
| “Какие пиковые нагрузки?” | Spike тестирование |
| “Какие эндпоинты самые критичные?” | Приоритеты |
| “Какое допустимое время ответа?” | SLO (Service Level Objective) |
| “Сколько пользователей одновременно?” | Конкуренция |
| “Какой профиль нагрузки?” | Равномерная, волнообразная, суточная |
Пример целевых показателей (SLO)
| Эндпоинт | Целевой RPS | p95 | p99 |
|---|---|---|---|
| GET /users | 500 | 100 мс | 200 мс |
| GET /users/{id} | 2000 | 50 мс | 100 мс |
| POST /orders | 100 | 300 мс | 500 мс |
| GET /reports | 10 | 5 с | 10 с |
Резюме
Нагрузочное тестирование — проверка производительности системы под нагрузкой. Ответы на вопросы: “Сколько выдержит?”, “Как быстро?”, “Где узкое место?”
Виды: Load (ожидаемая нагрузка), Stress (до разрушения), Soak (длительная), Spike (резкий скачок).
Ключевые метрики: время отклика (p50, p95, p99), пропускная способность (RPS), потребление ресурсов (CPU, RAM), процент ошибок.
Инструменты: k6 (современный, простой), JMeter (классика), Locust (гибкий).
Сценарии: постепенное увеличение, постоянная нагрузка, пик, нагрузка до разрушения.
Анализ: искать узкие места (БД, сеть, приложение, кеш). Смотреть на перцентили, не на среднее.
В CI/CD: нагрузочные тесты обычно запускаются ночью, не на каждый коммит. Нужен стенд, похожий на production.