Метрики нагрузочного тестирования: RPS, latency, percentiles и их правильная интерпретация
Вступление
В нагрузочном тестировании проблема почти никогда не в том, что «мы не можем запустить тест». Проблема — в том, что после запуска мы не понимаем, что означают цифры.
Перед тем как запускать нагрузочное тестирование, важно ответить на простой вопрос: а что именно мы будем измерять и зачем?
На практике часто происходит обратное. Тест запускают, получают набор графиков и цифр — и дальше начинается попытка «угадать», что всё это значит. Система выдержала нагрузку или нет? Стало лучше по сравнению с прошлым запуском? Где узкое место? Ответов нет, потому что изначально не было понимания, какие метрики важны и как их интерпретировать.
Метрики — это не просто цифры в отчёте. Это инструмент для принятия решений: сравнить результаты с бейслайном, понять поведение системы под нагрузкой и корректно выбрать профиль нагрузки. Без этого нагрузочное тестирование легко превращается в формальность — вроде что-то прогнали, но реальной ценности не получили.
Важно: метрики всегда зависят от цели теста
Один и тот же набор метрик может интерпретироваться по-разному в зависимости от типа тестирования.
В этой статье мы говорим про классическое нагрузочное тестирование (load), где цель — понять, как система ведёт себя при ожидаемой нагрузке: выдерживает ли она её, укладывается ли в SLA, есть ли запас.
Но если это стресс-тест — вас уже интересует, где система «ломается». Там нормой становится рост ошибок и деградация latency.
В тестах на отказоустойчивость (resilience / chaos) метрики читаются ещё иначе: ошибки и деградация допустимы, если система корректно восстанавливается.
Поэтому прежде чем анализировать цифры, всегда нужно зафиксировать контекст: что именно мы сейчас проверяем и какой результат считаем «нормальным».
1. Основные метрики отклика
Response Time (время отклика)
Когда говорят про производительность системы, почти всегда имеют в виду именно время отклика — сколько прошло от отправки запроса до получения полного ответа.
На первый взгляд всё просто. На практике — это одна из самых неправильно интерпретируемых метрик.
Главная проблема в том, что Response Time — это не одно число, а распределение значений. И если смотреть на него неправильно, можно прийти к полностью неверным выводам о системе.
Average Response Time (среднее)

Первое, на что обычно смотрят — среднее время отклика. И это самая опасная метрика, если использовать её в отрыве от остальных.
Классическая ситуация: 9 запросов отработали за 100 мс, один — за 5 секунд. Среднее получится около 590 мс.
Если смотреть только на average, создаётся ощущение, что система «тормозит».
Но в реальности 90% пользователей получили быстрый ответ.
Бывает и наоборот. Например, половина запросов — 100 мс, половина — 900 мс. Среднее около 500 мс выглядит «приемлемо», но фактически половина пользователей уже сталкивается с заметной задержкой.
Среднее значение удобно для общего ориентира, но на него нельзя опираться при принятии решений.
Median (P50)

Медиана показывает, как ведёт себя «типичный» пользователь.
Это значение, ниже которого укладывается 50% всех запросов. В отличие от среднего, медиана почти не чувствительна к редким выбросам.
Если P50 = 120 мс — значит, половина пользователей получает ответ быстрее этого значения. Это хороший индикатор «нормального» поведения системы.
Но медиана не показывает проблем на хвостах — а именно там чаще всего и скрываются реальные деградации.
Percentiles (P90, P95, P99)

Процентили — это главный инструмент анализа времени отклика.
Например: P95 = 1500 мс означает, что 95% запросов завершились быстрее 1.5 секунды, а оставшиеся 5% — медленнее.
И именно эти 5% — это реальные пользовательские проблемы. Это те случаи, когда интерфейс «подвис», операция выполняется слишком долго или пользователь начинает повторно нажимать кнопку.
P99 показывает ещё более «тяжёлый хвост». Если он сильно отличается от P95, это сигнал, что в системе есть редкие, но очень долгие операции. На практике это часто:
- блокировки в базе,
- асинхронная обработка / очереди,
- медленные внешние сервисы,
- деградация под нагрузкой.
Именно поэтому в SLA почти всегда фигурируют процентили, а не среднее.
Min / Max Response Time

Минимум и максимум часто игнорируют, но они тоже дают полезный контекст.
Минимальное значение показывает «идеальный сценарий» — когда всё отработало быстро, без конкуренции за ресурсы.
Максимальное значение, наоборот, помогает быстро увидеть проблемы. Если max уходит в десятки секунд — это почти всегда таймауты, зависшие запросы или проблемы на уровне инфраструктуры.
Average vs Percentiles — короткое правило
Если смотреть только на среднее — можно легко обмануть себя и команду.
Если смотреть на P95 и P99 — становится видно, как система ведёт себя под нагрузкой на самом деле.
Именно поэтому в реальных проектах ключевые решения почти всегда принимаются по процентилям, а не по average.
2. Метрики нагрузки
Если метрики отклика отвечают на вопрос «насколько быстро работает система», то метрики нагрузки — это про «сколько она вообще может переварить».
И здесь тоже есть несколько распространённых заблуждений, которые регулярно ломают интерпретацию тестов.
RPS (Requests per Second)

RPS — это количество запросов, которое система обрабатывает в секунду. По сути, это основной показатель пропускной способности.
Именно через RPS обычно оценивают, выдерживает ли система целевую нагрузку. Например, если сервис стабильно держит 100 RPS при P95 = 300 мс — это уже осмысленный результат, который можно сравнивать с требованиями или бейслайном.
Но важно понимать: RPS сам по себе ничего не говорит о качестве работы системы.
Можно легко получить высокий RPS ценой деградации:
- растёт время отклика,
- увеличивается количество ошибок,
- пользователи начинают «ждать».
Поэтому RPS всегда нужно смотреть вместе с latency и error rate.
Throughput
Throughput часто путают с RPS, хотя это чуть более широкое понятие.
Если RPS — это количество запросов, то throughput может означать объём данных, проходящих через систему за единицу времени. Например, MB/s.
Это становится критичным в сценариях:
- загрузки и скачивания файлов,
- стриминга,
- работы с большими payload’ами.
Два сервиса могут показывать одинаковый RPS, но радикально отличаться по throughput — просто потому, что один гоняет JSON на 1 КБ, а другой — файлы по 10 МБ.
Virtual Users (VUs)

Virtual Users — это количество пользователей, которых вы эмулируете в тесте. Это не реальные пользователи, а их модель: сценарии, действия, задержки, последовательность запросов.
И здесь часто возникает первая ошибка: VU ≠ нагрузка. 100 VU — это не «100 запросов в секунду» и даже не обязательно «много».
Например, если каждый пользователь делает один запрос раз в 10 секунд, то: 100 VU → всего ~10 RPS.
И наоборот, 10 VU могут генерировать сотни RPS, если они работают без пауз.
Concurrent Users (одновременные пользователи)
Это количество пользователей, которые в конкретный момент времени активны: отправляют запрос, ждут ответ или находятся в процессе выполнения сценария.
Разница с VU тонкая, но важная. VU — это «сколько пользователей мы создали». Concurrent users — это «сколько из них сейчас реально нагружают систему».
Например, если у вас есть think time между действиями, часть пользователей в каждый момент времени просто «думает» и не создаёт нагрузку.
Поэтому 100 VU не означает 100 одновременных запросов.
Связка VU → RPS (ключевая мысль)
Один из самых частых вопросов: «Сколько нужно пользователей, чтобы получить 200 RPS?»
Ответ: зависит от сценария.
RPS — это производная от:
- количества VU,
- скорости выполнения сценария,
- think time,
- времени отклика системы.
Поэтому правильный подход — не «выставить VU», а контролировать RPS или хотя бы понимать, как он формируется.
Latency vs Response Time
Эти термины часто используют как синонимы, но между ними есть разница.
Latency — это время до получения первого байта ответа.
Response Time — это время до получения полного ответа.
В простых API разница может быть незаметной. Но в реальных системах (стриминг, большие ответы, медленные сети) она становится критичной.
Пример: сервер начал отвечать быстро (низкая latency), но сам ответ «льётся» 2 секунды. Пользователь всё равно ждёт эти 2 секунды — и для него важен именно response time.
3. Метрики ошибок
Если время отклика показывает, насколько быстро работает система, то метрики ошибок отвечают на более жёсткий вопрос: а работает ли она вообще стабильно под нагрузкой?
И здесь важно не просто увидеть «есть ошибки или нет», а понять их природу.
Error Rate

Error Rate — это процент запросов, завершившихся с ошибкой.
На первый взгляд всё просто: если из 10 000 запросов 50 завершились неуспешно, значит error rate = 0.5%. Но ключевой момент — какие именно это ошибки.
Одинаковый error rate может означать совершенно разные проблемы:
- 0.5% 500-х ошибок → система не справляется под нагрузкой
- 0.5% таймаутов → система слишком медленная
- 0.5% 4xx → возможно, проблема вообще в тестовых данных или сценарии
Поэтому сам по себе процент — это только сигнал. Разбираться нужно глубже.
HTTP Status Code Distribution
Распределение по статус-кодам — это первый шаг к пониманию, что происходит.
- Если растут 5xx — почти всегда проблема на стороне сервера: перегрузка, ошибки в коде, проблемы с зависимостями.
- Если растут 4xx — это уже вопрос к сценарию: невалидные данные, неправильная последовательность действий, истёкшие токены.
Типичный кейс: запустили нагрузку, увидели 10% ошибок — паника. Начали разбираться — оказалось, половина из них 401, потому что токен не обновлялся.
И это уже не проблема производительности.
Timeouts
Таймауты — один из самых неприятных типов ошибок. Они означают, что система не успела ответить за отведённое время.
И здесь важно понимать: таймаут — это не просто ошибка, это уже симптом деградации.
Часто это выглядит так:
- растёт нагрузка,
- увеличивается P95 / P99,
- затем начинают появляться таймауты.
То есть таймауты — это, по сути, «продолжение» проблем с latency.
Connection Errors
Connection errors возникают ещё до обработки запроса — на этапе установки соединения.
Это могут быть:
- проблемы с TCP,
- ошибки SSL,
- отказ в соединении (connection refused).
Такие ошибки часто указывают на инфраструктурные ограничения:
- переполненные connection pool’ы,
- лимиты на уровне балансировщика,
- исчерпанные ресурсы (например, file descriptors).
Если при росте нагрузки начинают появляться connection errors — это почти всегда сигнал, что система «ломается» на уровне инфраструктуры, а не бизнес-логики.
4. Продвинутые метрики
Эти метрики реже обсуждают на старте, но именно они часто объясняют, почему система ведёт себя так, а не иначе.
Если базовые метрики отвечают на вопрос «что происходит», то продвинутые — «почему это происходит».
Think Time и Pacing
Think Time — это пауза между действиями пользователя. В реальной жизни никто не делает 10 запросов подряд без остановки: пользователь читает, думает, кликает.
В нагрузочном тесте это поведение нужно моделировать явно.
Если этого не делать, получается синтетическая нагрузка, которая не имеет ничего общего с реальностью. Например, 100 пользователей начинают «долбить» API без пауз — и система падает. Возникает вопрос: проблема в системе или в тесте?
Чаще всего — в тесте.
Pacing решает немного другую задачу. Это контроль частоты выполнения сценария одним пользователем. Например, можно задать, что один пользователь проходит сценарий не чаще одного раза в 10 секунд, независимо от того, как быстро он завершился.
На практике think time делает поведение реалистичным, а pacing — предсказуемым.
Dropped Requests и Retries
Под нагрузкой система может начать «отбрасывать» запросы.
Dropped requests — это ситуации, когда соединение разрывается или запрос не доходит до обработки. Часто это происходит на уровне балансировщиков или прокси, когда ресурсы исчерпаны.
Это важный сигнал: система уже не просто замедляется, она начинает терять запросы.
Retries — это обратная сторона. Клиент (или тест) может автоматически повторять запросы после ошибки.
И здесь кроется опасный эффект: система начинает деградировать → появляются ошибки → включаются ретраи → нагрузка ещё больше растёт → система деградирует ещё сильнее.
В итоге можно получить «лавину», когда сами ретраи усиливают проблему. Если в тесте используются retries, их нужно обязательно учитывать при анализе — иначе RPS и error rate будут искажены.
CPU Time per Request

Эта метрика показывает, сколько процессорного времени тратится на обработку одного запроса.
Её редко смотрят напрямую, но она очень полезна для понимания масштабируемости.
Простой пример: если один запрос требует 50 мс CPU, а у вас есть 1 CPU-секунда в секунду, то теоретический предел — около 20 RPS на ядро.
Если при росте нагрузки CPU стремится к 100%, а время отклика растёт — это явный признак CPU-bound системы. В этом случае горизонтальное масштабирование или оптимизация кода могут дать быстрый эффект.
Если же CPU загружен на 30%, а latency всё равно высокий — значит, узкое место где-то ещё: база данных, сеть, внешние сервисы.
Сводная таблица метрик (шпаргалка)
| Метрика | Что измеряет | Зачем нужна | Как интерпретировать |
|---|---|---|---|
| Response Time | Полное время ответа | Общая производительность | Смотреть только в распределении, не как одно число |
| Average (avg) | Среднее время | Быстрая оценка | Часто вводит в заблуждение из-за выбросов |
| Median (P50) | «Типичный» пользователь | Понимание нормального поведения | Хорошо показывает базовый UX, но скрывает проблемы |
| P90 / P95 / P99 | Хвосты распределения | SLA, реальный UX | Ключевая метрика: показывает деградацию и проблемы |
| Min / Max | Лучший / худший кейс | Поиск аномалий | Max помогает ловить таймауты и зависания |
| RPS | Запросы в секунду | Пропускная способность | Всегда смотреть вместе с latency и error rate |
| Throughput | Объём данных (MB/s) | Data-heavy сценарии | Важен для файлов, стриминга, больших payload |
| Virtual Users (VU) | Количество пользователей | Модель нагрузки | Сам по себе ничего не значит без сценария |
| Concurrent Users | Активные пользователи | Реальная нагрузка | Может сильно отличаться от VU |
| Latency | Время до первого байта | Сетевые и streaming сценарии | Может быть низким при высоком response time |
| Error Rate | % ошибок | Стабильность системы | Нужно анализировать по типам ошибок |
| HTTP Codes | 200 / 4xx / 5xx | Диагностика | 5xx — сервер, 4xx — чаще сценарий |
| Timeouts | Неуспевшие ответы | Деградация | Обычно следствие роста latency |
| Connection Errors | Ошибки соединения | Инфраструктура | Часто лимиты или перегрузка |
| Think Time | Паузы пользователя | Реализм нагрузки | Без него тесты нереалистичны |
| Pacing | Частота сценария | Контроль нагрузки | Делает тест предсказуемым |
| Dropped Requests | Потерянные запросы | Критическая деградация | Система уже не справляется |
| Retries | Повторные запросы | Поведение клиента | Может усиливать нагрузку и искажать метрики |
| CPU / Request | CPU на запрос | Масштабируемость | Позволяет оценить предел RPS на ядро |
Пример интерпретации
Представим, вы запустили нагрузочный тест и получили такие цифры:
- RPS = 200
- P95 = 950 мс
- P99 = 1800 мс
- Error Rate = 0.7%
- CPU = 90%
- RAM = 65%
Теперь самое интересное — как это читать.
Первое, на что стоит посмотреть — это связка RPS и latency. 200 RPS при P95 < 1 секунды — это, в целом, хороший результат. Система держит нагрузку и не уходит в критическую деградацию. Если это соответствует целевому профилю — уже неплохо.
Но дальше смотрим на P99. 1.8 секунды — это заметный разрыв с P95. Значит, есть «тяжёлый хвост»: небольшая часть запросов выполняется сильно дольше остальных. И это как раз те самые пользователи, которые будут жаловаться, что «иногда всё подвисает».
Следующий шаг — ошибки. 0.7% — вроде бы небольшая цифра, но в абсолютных значениях это уже ощутимо. При 200 RPS это примерно 1–2 ошибки в секунду. И вот тут важно не число само по себе, а природа ошибок.
Если это таймауты — значит, система не успевает обрабатывать часть запросов.
Если 5xx — возможно, уже есть деградация под нагрузкой.
Если 4xx — возможно, проблема вообще в сценарии.
Дальше — CPU. 90% загрузки — это почти потолок. Это сильный сигнал, что система близка к своему пределу. В таком состоянии любое увеличение нагрузки, скорее всего, приведёт к росту latency и ошибок.
И вот здесь появляется важный вывод: даже если сейчас «всё вроде нормально», запас по производительности почти отсутствует.
RAM при этом на уровне 65% — значит, память не является узким местом. Можно сфокусироваться именно на CPU: профилирование, оптимизация, масштабирование.
Итоговое чтение ситуации
Система в текущей точке работает стабильно, но уже на грани:
- нагрузку держит,
- но есть проблемы на хвостах (P99),
- появляются ошибки,
- CPU почти упёрся в лимит.
Это классический момент, когда тест ещё «зелёный», но инженер уже понимает:
дальше без оптимизации или масштабирования будет только хуже.
Заключение
Метрики сами по себе ничего не значат — важна их связка и правильная интерпретация. Именно это отличает «прогон нагрузки» от настоящего инженерного анализа системы.