Нагрузочный тест показывает низкую задержку, хотя пользователи жалуются на медленные ответы. Какой дефект методики измерения может это объяснить?
Это может быть скоординированное упущение измерений — coordinated omission. Нагрузчик отправляет следующий запрос только после завершения предыдущего и поэтому не учитывает время, в течение которого система была перегружена, но новый запрос ещё не был отправлен. В результате тест занижает реальную задержку и скрывает длинные паузы обслуживания.
Проблема возникла из-за распространённого способа построения простых нагрузочных генераторов: один виртуальный пользователь отправляет запрос, ждёт ответ и затем начинает следующий. Такой подход удобен для моделирования последовательных операций, но плохо отражает фиксированный поток запросов и не показывает задержки, которые пользователь испытывает во время остановки или деградации сервиса.
Для систем реального времени особенно важно измерять не только скорость успешно завершённых операций, но и влияние перегрузки на весь поток запросов. Поэтому появились методики, отделяющие расписание отправки запросов от фактического времени их завершения.
Предположим, сервис обычно отвечает за 20 миллисекунд, но периодически занят 5 секунд. Наивный генератор, ожидающий завершения запроса, в течение этих 5 секунд не создаёт новые измерения. После восстановления он снова получает быстрые ответы и формирует хорошую статистику.
Пользовательский трафик ведёт себя иначе: запросы продолжают поступать по расписанию. Они накапливаются, ждут обработки и получают большие задержки или таймауты. Если ориентироваться на искажённые результаты теста, можно ошибочно решить, что система выдерживает нагрузку, и не обнаружить риск лавинообразного роста очереди.
При скоординированном упущении измеритель связывает отправку следующего запроса с завершением предыдущего. Когда сервис замедляется, генератор сам снижает интенсивность нагрузки именно в тот момент, когда нужно проверить поведение системы под давлением. Измеряются преимущественно запросы, которым повезло попасть в периоды нормальной работы.
Корректнее задавать независимый график поступления запросов или использовать модель открытой системы, где новые запросы могут приходить независимо от завершения старых. Для каждого запланированного запроса нужно учитывать задержку от его исходного времени отправки, а не только время выполнения уже принятого системой запроса.
Полезно сравнивать несколько показателей: распределение задержек, долю таймаутов, глубину очередей, фактическую интенсивность входящего потока и пропускную способность. Если генератор ограничивает число одновременных запросов, это ограничение нужно явно учитывать: оно может быть частью сценария закрытой системы, но не должно маскировать поведение открытого пользовательского трафика.
Исправление методики не означает, что любое последовательное измерение неверно. Для операции, где один запрос действительно невозможен до завершения предыдущего, такая модель может быть реалистичной. Компромисс заключается в выборе модели нагрузки: закрытая модель лучше описывает ограниченное число клиентов, а открытая — поток запросов, который продолжает поступать независимо от текущей занятости сервиса.
Команда тестировала API перед запуском рекламной кампании. Генератор с фиксированным числом виртуальных пользователей показывал p99 около 200 миллисекунд, но в рабочей среде пользователи сталкивались с задержками в несколько секунд. При разборе выяснилось, что каждый виртуальный пользователь ждал ответа перед отправкой следующего запроса; во время зависания сервиса генератор фактически снижал нагрузку.
Рассматривались два варианта. Увеличение числа виртуальных пользователей могло приблизить нагрузку к реальной, но оставляло искажение измерений и усложняло интерпретацию результатов. Переход к независимому расписанию отправки лучше отражал входящий поток, но требовал контролировать рост очереди запросов и корректно обрабатывать ответы, пришедшие с опозданием.
Выбрали второй вариант и дополнительно ввели измерение задержки относительно запланированного времени отправки. После этого тест показал длинный хвост задержек и таймауты, ранее скрытые генератором. Команда обнаружила ограничение в downstream-зависимости и снизила максимальный поток до уровня, при котором SLO сохранялся.
1. Достаточно ли просто увеличить число виртуальных пользователей, чтобы устранить проблему?
Нет. Это может частично увеличить давление на сервис, но не устраняет сам механизм искажения. Каждый виртуальный пользователь всё ещё может прекращать отправку запросов во время ожидания, а полученная интенсивность будет зависеть от текущей задержки системы. Кроме того, результат станет труднее сопоставлять с реальным расписанием трафика.
Нужно проверить, какая модель нагрузки требуется: закрытая или открытая. При открытой модели отправка определяется заданным потоком, а не завершением предыдущих операций; при закрытой важно явно понимать, что число активных клиентов ограничено и их естественное ожидание является частью сценария.
2. Почему средняя задержка может выглядеть нормальной даже при серьёзной перегрузке?
Потому что среднее значение чувствительно к тому, какие запросы вообще попали в выборку. Если во время перегрузки новые запросы не создаются или задержавшиеся операции не учитываются от момента их плановой отправки, статистика состоит в основном из быстрых периодов.
Даже при корректном сборе среднее может скрывать редкие, но длительные задержки. Поэтому нужно анализировать квантили, таймауты, долю отклонённых запросов и задержку по времени, а не только одну агрегированную цифру. Для SLO также важно заранее определить, какие запросы считаются успешными и как учитываются таймауты.
3. Может ли корректный генератор сам создать нереалистичную ситуацию?
Да. Открытая модель продолжает подавать запросы при замедлении сервиса, поэтому очередь может быстро расти и привести к исчерпанию памяти или ресурсов генератора. Это не обязательно ошибка теста: такой результат показывает, что при заданной интенсивности система не успевает обслуживать поток.
Однако сценарий должен иметь защитные ограничения: длительность теста, максимальный объём ожидающих запросов, правила остановки и наблюдаемость самого генератора. Иначе можно перепутать отказ тестового стенда с отказом проверяемой системы. Корректный тест одновременно сохраняет реалистичную модель нагрузки и позволяет отделить пределы генератора от пределов сервиса.