Нагрузочное тестирование HTTP-запроса
Узел HTTP-запрос может отправить свой запрос много раз подряд, по профилю с заданным числом запросов в секунду, по многу сразу, — и измерить, что вернулось: процентили задержки, ошибки, достигнутый темп. Пороги решают, проходит ли шаг, а кнопка Сравнить ставит эти числа рядом с числами предыдущего запуска.
Нагрузка — это настройка узла, а не отдельный узел: остальная часть эксперимента — эмуляторы, реле помех, другие ветки — работает вокруг неё как обычно.
Как включить нагрузку
- Выберите узел HTTP-запрос и заполните его запрос.
- В его свойствах установите флажок отправлять под нагрузкой.
- Выберите Профиль и задайте его числа. График под ними, Темп во времени, рисует темп и показывает, сколько всего получается запросов и за сколько секунд.
- Укажите в поле Одновременно, сколько запросов может быть в пути одновременно.
- Добавьте или измените Пороги.
- Запустите эксперимент.
По умолчанию нагрузка — профиль Рост от 0 до 100 запросов в секунду за 30 000 мс, 32 одновременно, с двумя порогами: p95 < 500 мс и Ошибки < 1 %.
Нагрузка заменяет серию отправок и повтор при ошибке. Если её включить, они выключаются, а узел с нагрузкой и любой из них отклоняется (node.load_alone): неудачный запрос подсчитывается, а не повторяется. Под нагрузкой может работать только HTTP-запрос (node.load_unsupported).
Запрос читается один раз. Его шаблоны подставляются в начале шага, поэтому все запросы нагрузки одинаковы: {{counter}} и {{uuid}} принимают одно значение для всех. См. шаблоны.
Один клиент на всю нагрузку. Запросы делят банку cookie запуска, когда установлен флажок Хранить cookie между запросами, и одну память Digest, так что одного вызова сервера хватает на все запросы. Каждый запрос ограничен тайм-аутом самого узла.
Инспектор получает выборку: не больше одного обмена каждые 100 мс, чтобы нагрузка не заваливала Инспектор.
Профили
| Профиль | Настройки | Темп во времени |
|---|---|---|
| Ровный | Темп, запр./с, Длительность, мс | один и тот же темп всё время |
| Рост | От, запр./с, До, запр./с, Длительность, мс | по прямой от одного темпа к другому |
| Ступени | От, запр./с, Шаг, запр./с, Каждая, мс, Ступеней | первый темп, затем на каждой ступени на шаг больше; каждая ступень длится одинаково |
| Всплеск | База, запр./с, Пик, запр./с, Всплеск с, мс, Всплеск длится, мс, Длительность, мс | базовый темп, с заданного момента на время — пиковый, затем снова базовый |
| Случайный | Темп, запр./с, Длительность, мс | приходы в случайные моменты, в среднем с заданным темпом |
При смене профиля сохраняется то, что можно перенести: сколько длится нагрузка и наибольший темп, которого она достигает.
Ограничения
| Настройка | Диапазон |
|---|---|
| Темп, запр./с у профилей Ровный и Случайный, Пик, запр./с | 0,1–100 000 запросов/с |
| От, запр./с, До, запр./с, База, запр./с | 0–100 000 запросов/с |
| Каждая ступень профиля Ступени, включая последнюю | 0–100 000 запросов/с; шаг может быть отрицательным |
| Длительность, мс, Каждая, мс | 100–300 000 мс |
| Ступеней | 1–100, а все ступени вместе — не больше 300 000 мс |
| Всплеск | дольше 0 мс и заканчивается до конца длительности |
| Одновременно | 1–512 |
| Пороги | не больше 16, каждое значение — число, 0 или больше |
Профиль, который в сумме не даёт ни одного запроса, отклоняется (load.nothing_planned). Диапазоны темпа — те же, что у нагрузочного потока HTTP.
Профиль может длиться столько же, сколько весь запуск, 300 с, — но ограничение времени запуска учитывает все шаги, так что оставьте запас для остального эксперимента.
Сколько запросов
Запросы профиля — это его темп, сложенный по времени:
| Профиль | Запросов |
|---|---|
| Ровный, 100/с в течение 1000 мс | 100 |
| Рост, 0 → 100/с за 2000 мс | 100 |
| Ступени, от 10/с с шагом 10/с, 3 ступени по 1000 мс | 60 (10 + 20 + 30) |
| Всплеск, 10/с со всплеском до 100/с с 1000 мс на 500 мс, всего 2000 мс | 65 |
| Случайный, 200/с в течение 10 000 мс | в среднем 2000 |
Расписание
n-й запрос назначается на тот момент, когда счёт профиля достигает n; первый — сразу. Каждый момент вычисляется от начала нагрузки, поэтому запоздалое пробуждение никогда не сдвигает следующие запросы, и темп, описанный профилем, — это и есть запрошенный темп.
Профиль Случайный выбирает промежутки между приходами случайно, из seed запуска: тот же seed даёт те же моменты, поэтому случайную нагрузку можно повторить в точности. См. seed.
Пропущенные запросы. В пути одновременно не больше запросов, чем задано в поле Одновременно. Когда все они ещё ждут ответа, следующий запрос ждёт свободного места. Если он ушёл бы больше чем через 50 мс после своего момента, его не отправляют с опозданием: он пропускается и считается пропущенным — вместе со всеми запросами, срок которых наступил за это время, — и нагрузка продолжается с первого запроса, который ещё успевает вовремя. Много пропущенных запросов означает, что сервер или значение Одновременно не поспевали за профилем.
Во время выполнения
Раз в секунду лента показывает шаг как Под нагрузкой — с прошедшими секундами, отправленными запросами, темпом за последнюю секунду, p95 на текущий момент и неудачными запросами. Кнопка Стоп сразу завершает нагрузку и бросает запросы, которые ещё в пути; сбой в другой ветке завершает её в течение секунды.
Что измеряется
После последнего ответа у шага есть измерения; они хранятся в его последнем событии на ленте и в отчёте о запуске:
| Измерение | Что это |
|---|---|
| planned | запросы, которые даёт профиль (Случайный — в среднем) |
| sent | запросы, получившие ответ или не прошедшие |
| ok | получили ответ со статусом 2xx |
| failed | любой другой статус или вообще без ответа |
| missed | срок наступил, когда все места были заняты, и запрос пропущен |
| rps | отправленных запросов в секунду: sent ÷ длительность профиля — или ÷ время до отправки последнего запроса, если оно больше |
| error_rate | failed в % от sent |
| min, mean, max | самый быстрый, средний и самый медленный запрос, мс |
| p50, p90, p95, p99 | задержка, которой не превысили 50, 90, 95 и 99 % запросов, мс |
| received_bytes | всего получено байт тела |
| statuses | запросы по статусу (200, 503), а без статуса — по причине (timeout, refused, reset …) |
| seconds | каждая секунда профиля: отправлено запросов, из них неудачных, их средняя задержка |
| histogram | запросы по задержке: до 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10 000 мс и медленнее |
Задержка запроса считается от отправки до чтения всего ответа, а неудачный запрос учитывается со временем, которое ушло на неудачу. Процентили берутся из логарифмических корзин шириной 1 % и отличаются от истинного значения не больше чем на 0,5 %, сколько бы ни шла нагрузка.
Пороги
Порог — это строка из полей Метрика, Сравнение и Значение; кнопка Порог добавляет ещё один.
| Метрика | В чём измеряется |
|---|---|
| p50, p90, p95, p99 | мс |
| Среднее, Самый медленный | мс |
| Ошибки | % от отправленных запросов |
| Темп | достигнутые запросы в секунду |
| Пропущено | запросы |
Поле Сравнение принимает одно из значений <, ≤, >, ≥. Несколько типичных порогов:
| Метрика | Сравнение | Значение | Шаг не проходит, когда |
|---|---|---|---|
| p95 | < | 300 | каждый двадцатый запрос или чаще длился 300 мс или дольше |
| Ошибки | < | 1 | не прошёл 1 % запросов или больше |
| Темп | ≥ | 180 | сервер не смог принять 180 запросов в секунду |
| Пропущено | ≤ | 0 | пришлось пропустить хотя бы один запрос |
В файле порог записывается как { "metric": "p95_ms", "op": "lt", "value": 300 }; метрики — p50_ms, p90_ms, p95_ms, p99_ms, mean_ms, max_ms, error_rate, rps и missed, сравнения — lt, le, gt и ge.
Пороги проверяются после последнего ответа, по порядку. Шаг не проходит на первом невыполненном пороге (load.threshold) — в сообщении будут порог и измеренное значение, — и запуск не проходит вместе с ним. Без порогов нагрузка проходит, что бы она ни намерила. Если нагрузку раньше времени завершил сбой другой ветки, это сбой запуска, а не порога.
Результат
Когда шаг проходит, лента подводит итог: запросы, темп, p95 и доля неудачных. Выберите узел: в его свойствах показан раздел Нагрузка в последнем прогоне —
- каждый порог, ✓ Выполнен или ✕ Не выполнен, с измеренным значением;
- Отправлено, Запр./с, Ошибки с их долей, Пропущено;
- p50, p90, p95, p99, Среднее, Макс;
- По секундам: запросы каждой секунды, неудачные — красным, а их средняя задержка — линией;
- Задержки: сколько запросов сколько длились;
- статусы и причины, у каждого — количество.
Командная строка печатает те же числа и вердикт по каждому порогу; см. signallab run.
Сравнение двух запусков
- Запустите эксперимент два раза или больше.
- На ленте нажмите Сравнить. Кнопка появляется, когда запуск сохранил свой отчёт, и недоступна, пока идёт запуск.
- Последний запуск — После, предыдущий — До; в любом из списков можно выбрать другой запуск.
В списках — запуски этого эксперимента (по его имени) из отчётов в папке данных, новые сверху, не больше 50: у каждого дата и время, чем он закончился, и его seed. Запуски из командной строки там тоже есть, если она использовала ту же папку данных. Переименование эксперимента начинает новую историю.
Для каждого шага с нагрузкой, сопоставленного по узлу, таблица показывает каждую метрику — До, После и Изменение — в единицах измерения и в %. Изменение в худшую сторону на 5 % или больше — медленнее, больше ошибок, больше пропущенных запросов, ниже темп — это регрессия, она выделяется красным; переход от нуля к чему-то тоже считается. Под таблицей — вердикт каждого порога в обоих запусках. Шаг с нагрузкой, который есть только в одном из запусков, помечен только до или только после, без изменений. Для запусков без шагов с нагрузкой показано В этих прогонах нет шагов с нагрузкой.
Из скрипта experiment_runs перечисляет запуски, а experiment_compare сравнивает два из них по имени файла отчёта; signallab mcp предлагает то же самое ассистенту (MCP).
Проверки после нагрузки
Нагрузка не оставляет собственного ответа: её измеряют, а не проверяют. Проверке или узлу Извлечь значение после неё нужен на каждом пути перед ними другой запрос без нагрузки, иначе эксперимент не запустится (graph.needs_http). Чтобы проверить один ответ API под нагрузкой, поставьте обычный HTTP-запрос после нагрузки или в параллельной ветке рядом с ней.
Кнопка Отправить сейчас на узле под нагрузкой отправляет его запрос один раз.