Нагрузочное тестирование с k6: как узнать пределы приложения
Практика4 минРедакция Innovialabs
Коротко
Напишите в k6 сценарий с реальными действиями пользователей, поднимайте нагрузку ступенями с порогами для p95 и ошибок, параллельно смотрите метрики сервера и устраняйте первое найденное узкое место перед повторным тестом.
Короткий ответ
k6 — инструмент нагрузочного тестирования с открытым исходным кодом: сценарии пишутся на JavaScript и запускаются из командной строки. Чтобы найти пределы приложения:
- Выберите критичные сценарии пользователей (вход, каталог, оформление заказа, поиск).
- Опишите их в k6 с реалистичными паузами и данными.
- Поднимайте нагрузку ступенями и задайте thresholds для задержки и ошибок.
- Во время прогона следите за серверной стороной: CPU, память, база данных, очереди.
- Найдите момент, где растут задержки или ошибки, устраните причину, повторите.
Цель — не большое число запросов в секунду, а понимание, при какой нагрузке ломается опыт пользователя и почему.
Первый сценарий
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 },
{ duration: '5m', target: 50 },
{ duration: '2m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('https://staging.example.com/api/products');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
Запуск: k6 run script.js. Здесь 50 виртуальных пользователей (VU) набираются за две минуты, держатся пять и плавно уходят. Пороги — примерные значения, замените их целями своего продукта. Если порог не выполнен, k6 завершается с ненулевым кодом, поэтому тест можно запускать в CI.
Реалистичный профиль нагрузки
Польза теста зависит от профиля нагрузки. Что важно сделать правильно:
- Сценарии, а не отдельные эндпоинты. Объединяйте запросы в том порядке, в каком их делает человек, и добавляйте
sleep()между шагами как время на размышление. - Разные данные. Используйте разные ID товаров, поисковые запросы и аккаунты, иначе кэш покажет нереально быструю картину.
- Открытая и закрытая модель. С VU медленный сервер заставляет пользователей ждать, и они шлют меньше запросов — проблема прячется. Executor’ы
constant-arrival-rateиramping-arrival-rateотправляют запросы с заданной частотой независимо от времени ответа, что ближе к реальному трафику. - Виды тестов. Короткий smoke проверяет сам скрипт; load — ожидаемый трафик; stress выходит за его пределы; spike добавляет резкий скачок; soak держит нагрузку часами и ловит утечки памяти и исчерпание соединений.
Тестируйте staging-окружение, похожее на продакшен. Если нужен тест продакшена, согласуйте окно времени и предупредите команду и внешних поставщиков.
Как читать результаты
В конце k6 выводит сводку. Самое важное:
| Метрика | Что показывает |
|---|---|
http_req_duration p(95), p(99) | Насколько медленны самые медленные 5% и 1% запросов |
http_req_duration avg | Сам по себе мало полезен: среднее скрывает длинный хвост |
http_req_failed | Доля неудачных запросов (сетевые ошибки, по умолчанию 4xx/5xx) |
checks | Пришло ли в ответах ожидаемое содержимое |
iterations | Сколько полных сценариев завершилось |
dropped_iterations | В arrival-rate тестах — запросы, которые k6 не смог начать: мало VU или перегружен генератор |
Смотрите на динамику во времени, а не только на сводку. Полезная находка — момент, когда p95 начинает резко расти или появляются ошибки, пока нагрузка ещё увеличивается. Это и есть практический предел.
Как превратить находки в исправления
Цифры задержки говорят лишь, что что-то медленно. Чтобы понять что, сопоставьте тест с метриками и логами сервера:
- CPU на пределе на серверах приложения: профилируйте горячий код, добавьте кэш, масштабируйтесь горизонтально.
- Узкое место — база: лог медленных запросов, недостающие индексы, N+1, слишком маленький пул соединений.
- Ошибки без высокого CPU: лимиты соединений и файловых дескрипторов, таймауты nginx или балансировщика, rate limits внешних API.
- Задержка медленно растёт в soak-тесте: утечки памяти, растущие очереди, незакрытые соединения.
Меняйте одну вещь за раз и повторяйте тот же скрипт, чтобы сравнение было честным. Храните скрипты в репозитории рядом с кодом.
Частые ошибки
- Генератор нагрузки сам упирается в CPU или канал и становится узким местом.
- Нет пауз, и несколько VU ведут себя как атака, а не как пользователи.
- Ошибки игнорируются, потому что задержка хорошая: быстрые ответы 500 — всё равно отказы.
- Тестируется только главная, хотя реальная нагрузка приходится на поиск и оформление заказа.
- Тест бьёт по сторонним платёжным или SMS API вместо заглушек.