Перейти к содержимому

Нагрузочное тестирование HTTP-запроса ​

Узел HTTP-запрос может отправить свой запрос много раз подряд, по профилю с заданным числом запросов в секунду, по многу сразу, — и измерить, что вернулось: процентили задержки, ошибки, достигнутый темп. Пороги решают, проходит ли шаг, а кнопка Сравнить ставит эти числа рядом с числами предыдущего запуска.

Нагрузка — это настройка узла, а не отдельный узел: остальная часть эксперимента — эмуляторы, реле помех, другие ветки — работает вокруг неё как обычно.

Как включить нагрузку ​

  1. Выберите узел HTTP-запрос и заполните его запрос.
  2. В его свойствах установите флажок отправлять под нагрузкой.
  3. Выберите Профиль и задайте его числа. График под ними, Темп во времени, рисует темп и показывает, сколько всего получается запросов и за сколько секунд.
  4. Укажите в поле Одновременно, сколько запросов может быть в пути одновременно.
  5. Добавьте или измените Пороги.
  6. Запустите эксперимент.

По умолчанию нагрузка — профиль Рост от 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_ratefailed в % от 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.

Сравнение двух запусков ​

  1. Запустите эксперимент два раза или больше.
  2. На ленте нажмите Сравнить. Кнопка появляется, когда запуск сохранил свой отчёт, и недоступна, пока идёт запуск.
  3. Последний запуск — После, предыдущий — До; в любом из списков можно выбрать другой запуск.

В списках — запуски этого эксперимента (по его имени) из отчётов в папке данных, новые сверху, не больше 50: у каждого дата и время, чем он закончился, и его seed. Запуски из командной строки там тоже есть, если она использовала ту же папку данных. Переименование эксперимента начинает новую историю.

Для каждого шага с нагрузкой, сопоставленного по узлу, таблица показывает каждую метрику — До, После и Изменение — в единицах измерения и в %. Изменение в худшую сторону на 5 % или больше — медленнее, больше ошибок, больше пропущенных запросов, ниже темп — это регрессия, она выделяется красным; переход от нуля к чему-то тоже считается. Под таблицей — вердикт каждого порога в обоих запусках. Шаг с нагрузкой, который есть только в одном из запусков, помечен только до или только после, без изменений. Для запусков без шагов с нагрузкой показано В этих прогонах нет шагов с нагрузкой.

Из скрипта experiment_runs перечисляет запуски, а experiment_compare сравнивает два из них по имени файла отчёта; signallab mcp предлагает то же самое ассистенту (MCP).

Проверки после нагрузки ​

Нагрузка не оставляет собственного ответа: её измеряют, а не проверяют. Проверке или узлу Извлечь значение после неё нужен на каждом пути перед ними другой запрос без нагрузки, иначе эксперимент не запустится (graph.needs_http). Чтобы проверить один ответ API под нагрузкой, поставьте обычный HTTP-запрос после нагрузки или в параллельной ветке рядом с ней.

Кнопка Отправить сейчас на узле под нагрузкой отправляет его запрос один раз.