В предыдущих частях я писал про установку k6, сценарии и визуализацию. Теперь — про самое сложное: как читать графики и отличать реальную проблему от шума.
Я долго боялся этой темы. Смотрел на графики и не понимал, с чего начать. Все линии растут, падают, скачут — и неясно, на что смотреть в первую очередь. Со временем я выработал простой порядок: сначала проверяю, что тест вообще валиден, потом смотрю на пропускную способность, потом на задержки, потом на распределение ошибок.
Здесь я расскажу, как я сейчас анализирую результаты. Без математической воды, только то, что помогает принять решение.
Шаг 1: Проверяю, что тест прошёл корректно
Перед тем как анализировать цифры, я смотрю на базовые вещи:
- Дошло ли нужное количество VU до конца прогона?
- Не упал ли сам генератор нагрузки по CPU или памяти?
- Совпадает ли количество запросов с ожидаемым?
Если k6 упал с out of memory, или VU не добрались до target, или запросов в 3 раза меньше, чем должно быть — анализировать метрики бессмысленно. Надо чинить инфраструктуру или скрипт.
Шаг 2: Смотрю на throughput (RPS)
Первый график, который я открываю — RPS (requests per second). Он показывает, сколько запросов в секунду приложение реально обрабатывает.
Что я ищу:
- Плато — приложение вышло на стабильную пропускную способность.
- Падение RPS при росте VU — значит, где-то bottleneck. Возможно, сервер начал отбрасывать запросы, или БД зависла.
- Скачки вниз — возможно, GC-паузы, перезапуски контейнеров, или срабатывание rate limiting.
Пример: я видел график, где RPS рос линейно до 400, потом резко упал до 200. Оказалось, что пул соединений с БД закончился, и новые запросы стали ждать.
Шаг 3: Задержки (response time)
Среднее время ответа — почти бесполезная метрика. Она скрывает выбросы. Я смотрю на процентили. Напомню из первой части: процентиль — это точка распределения, а не отдельная метрика. «p95 = 400 мс» значит, что 95% запросов уложились в 400 мс или быстрее. И считать их можно по разным метрикам: полная длительность запроса, время до первого байта, время получения ответа — в k6 это http_req_duration, http_req_waiting, http_req_receiving соответственно. Дальше везде я говорю про процентили полной длительности запроса:
- p50 (медиана) — половина запросов быстрее этого значения, половина медленнее. Ближайший аналог «типичного» времени ответа, но устойчивый к выбросам.
- p95 — «худший нормальный» случай: 95% запросов быстрее этой отметки. Обычно именно его берут в SLA.
- p99 — хвост распределения: самый медленный процент. Полезен, чтобы ловить выбросы, но при малом объёме запросов скачет из-за статистики.
Если p50 стабилен, а p95 растёт — значит, появляется «хвост» медленных запросов. Обычно это означает, что какой-то ресурс заканчивается: соединения, потоки, память.
Если растут и p50, и p95 — приложение реально тормозит под нагрузкой.
Шаг 4: Ошибки и статус-коды
График статус-кодов часто говорит больше, чем latency. Я смотрю:
| Коды | О чём говорят | Что делаю |
|---|---|---|
| 500+ | Приложение падает | Смотрю логи, ищу первый по времени кейс |
| 502 / 503 / 504 | Проблема на уровне балансировщика или прокси, либо приложение не успевает отвечать | Проверяю health-checks, таймауты прокси и очередь перед приложением |
| 429 | Сработал rate limiter | Пересматриваю настройки теста или прошу исключение для генератора |
| 400 | Скрипт шлёт некорректные данные | Проверяю payload и тестовые данные |
Важное правило: не считайте тест успешным, если есть хоть один 500-й код. Даже 0.1% ошибок при миллионах запросов — это тысячи реальных пользователей.
Шаг 5: Коррелирую с метриками сервера
Графики k6 — это вид со стороны клиента. Чтобы понять причину, я смотрю на метрики сервера в тот же интервал:
- CPU — если 100%, значит, не хватает вычислительной мощности.
- Память — если растёт и не падает, возможна утечка.
- Соединения с БД — если все заняты, запросы ждут.
- Диск I/O — иногда bottleneck вовсе не в CPU, а в медленных запросах к БД.
Пример из практики: latency росла, CPU был 40%. Я сначала думал, что проблема в коде. Потом посмотрел на БД — active connections забиты, slow queries пошли. Оптимизировал один индекс, и p95 упала в 4 раза.
Шаг 6: Сравниваю прогоны между собой
Один прогон — это точка. Чтобы увидеть тренд, я сравниваю несколько прогонов:
- До оптимизации и после.
- С разным количеством VU.
- С разными сценариями.
Я сохраняю результаты k6 в JSON или отправляю в InfluxDB с тегом версии. Так можно наложить графики друг на друга и увидеть, помогло ли изменение.
Частые ложные тревоги
Не всё, что растёт на графике, — проблема:
- Warm-up — первые 30-60 секунд обычно медленнее. Не принимайте их за реальный результат.
- Одиночные пики — могут быть связаны с GC, деплоем соседнего сервиса, или фоновой задачей. Смотрите на тренд, а не на отдельные точки.
- p99 скачет при малом трафике — если RPS низкий, p99 может прыгать просто из-за статистики. Доверяйте ему только при достаточном объёме данных.
Мой минимальный чек-лист
Когда открываю дашборд после прогона, я иду по этому списку:
- VU дошли до target и держались до конца?
- RPS стабилен или растёт плавно?
- p50 и p95 в пределах SLA?
- Есть ли ошибки? Какие?
- CPU/память/БД на стенде в норме?
- Есть ли корреляция между ростом latency и метриками сервера?
- Результат воспроизводится при повторном прогоне?
Что дальше
Нагрузочное тестирование — не разовая акция. Я запускаю его перед релизами, после крупных рефакторингов, когда меняю инфраструктуру. Иногда — просто чтобы убедиться, что цифры не ухудшились.
Главное, что я вынес за эти прогоны: метрики бессмысленны без контекста. Всегда начинайте с вопроса «что мы проверяем?», а не с графиков. Графики — инструмент ответа, а не замена вопросу.
Если остались вопросы — пишите в комментариях, разберу конкретные случаи.
Обсуждение
Комментариев пока нет — начните тему.