Оглавление
-
Составляем МНТ (Методику нагрузочного тестирования)
Нагрузочные скрипты
Инструменты для генерации нагрузки
Подготовка тестовых данных
Настройка генератора нагрузки и мониторинга
Отладка, пробные запуски
-
Основные метрики производительности
App-side метрики
Server-side метрики
Проведение тестирования
Контрольная проверка
Прогрев (warm-up)
-
Основная фаза теста
Что делает нагрузочник во время теста
Во время теста важно
Фиксация ключевых событий
Пост-нагрузочная стабилизация
Сбор результатов
Составление отчёта
Нагрузочное тестирование
Введение
Сегодня мы поговорим о нагрузочном тестировании. Той самой дисциплине, которая требуется в каждом проекте, но вспоминают о ней только тогда, когда система уже горит, а менеджеры уже успели пообещать клиенту, что «это не повторится». Сразу — не надо так!
Мы рассмотрим базовые понятия. Без академизма, потому что трудно оставаться полностью серьёзным, когда видишь, как систему нагружают 10 тысячами пользователей, а она написана так, будто её автор рассчитывал на трёх с половиной человек и одного стажёра.
Что такое нагрузка и почему она ломает всё подряд
Некто пользуется нашим приложением — у него есть на это причина. В курилке он рассказал, что функционал нового продукта инновационнен, новость разлетелась по всему району. Вчера было 1 скачивание, а сегодня уже аж 1000. Интересно, будут ли клиенты также довольны через пару дней? Пока всё здорово: функционал продуман до мелочей и работает как часы, создатели сервиса счасливы, показатели идут вверх. Проходит некоторое время, уже 10 000 скачиваний, однако в отзывах всё чаще стали появялться обидные сообщения в духе: «Это полный кошмар! Таких тормозов я ещё нигде не встречал(‑а). Что‑то крутится‑вертится бесконечно. Сами пользуйтесь своей поделкой! Всего хорошего!». Что же мы сделали не так? Босс компании в ярости. Лицо красное. Звонок:
— Босс, ну мы это, забыли провести нагруку!
— Чего забыли?
— Ну это, у нас были данные от аналитиков, что нашим инновационным и неповторимым сервисом будет скоро пользоваться очень много людей. Там в какой‑то курилке рассказали о нашем творении. Ну и понеслось. Если кратко: не выдерживаем, хана системе, нужно срочно масштабироваться. Сейчас сделаем, что в наших силах, но неизвестно — насколько долго это поможет.
— Так почему вы заранее не предусмотрели такое развитие событий?
— Ну как, на каждом викли в течение месяца до релиза я вам говорил, что нам следует взять человека, скиллового нагрузочника, способного сымитировать тысячи пользователей с их запросами, но вы говорили, что «ваши друзья уже пользуются приложением и пребывают в восторге, какой ещё нагрузочник? Мне деньги что ли некуда девать?», ну а после — тема уже затихла. А сейчас вот такая вот беда уже.
— …
Нагрузка — это не абстрактное зло. Это обычные люди, клиенты, мобильные приложения, фоновые задачи и автоматизированные процессы. Вы — та самая нагрузка, к примеру, для Ozon, Wildberries, гугла и так далее
Система должна выдерживать не идеальные условия, а реальные. Те самые, где пользователь может нажать на кнопку пять раз подряд, потому что интерфейс «не отвечает», а API — отвечает, но уже в слезах.
Если хотите проверить пределы системы, то не нужно ждать катастрофу. Можно стать этой катастрофой, запланировать заранее и устроить собственноручно в контролируемых условиях — такой подход и называется нагрузочным тестированием.
Нам всё равно, что делает эта система, но мы хотим знать как она это делает, насколько быстро и качественно.
Примеры провалов систем
Пример 1. Университет запускает тест в электронной образовательной системе (в моё время в МГТУ был в моде Moodle). В час ночи 700 студентов, торжественно окончив лютый вписон в общаге, одновременно начинают проходить тесты (после получения скринов всех вопросов и ответов от самого ответсвенного студента в группе, который завершил тест с высшим баллом ещё в 19:00 предыдущего дня). Система зависает. У всех ошибки, а у кого‑то вообще засчиталось всё по нулям. Почему? Потому что система протестирована на 10 запросах в минуту, а не на реальный всплеск нагрузки.
Пример 2. Сервис доставки выкатывает акцию. Половина пользователей видит спиннер, другая половина — цену ноль рублей. Наглядный урок о том, что интеграционные цепочки между сервисами тоже падают.
Пример 3. Чатбот. Вечер. Все сдают домашку. Бот переходит в режим созерцательной медитации и отвечает фразами, не предусмотренными ТЗ.
Типы нагрузочных тестов
В общем, вы поняли, что если система работает отлично, когда ей пользуется 5 человек, 10, или, может быть даже, когда — 1000, то это совсем не факт, что она будет также хорошо справляться при 10000, а, возможно, уже и при — 1001.
Наобум выбирать и тестировать неизвестным образом систему — плохая идея. Поэтому нам нужно заранее понять, что мы хотим сделать, как реализовать тест, и что дальше делать с полученными результатами.
Начнём с того, что имеются различные типы нагрузочных тестов, предназначенные для разных целей и задач. Все они на самом деле являются разновидностями более общего понятия: Тестирования Производительности (Performance Testing). Во время всех этих тестов на систему оказывается нагрузка в виде запросов из генератора по различным протоколам. Поэтому, когда вам говорят о нагрузке, то разговор плавно сворачивает в сторону тестирования производительности в целом. Нефункциональном виде тестов подопытной системы.
К сожалению, не существует какого‑то чёткого стандарта, что разложил бы Performance Testing по полочкам, но как эти тесты не назови, всё сводится к следующему:
Нагрузочное тестирование (Load Testing)
Достаточно ли быстро работает система при ожидаемой нагрузке? Проверяются SLA, задержки, ошибки.
Тестирование стабильности (Stability/Endurance/Soak Testing)
Насколько надёжно работает система длительное время. Ищем утечки памяти, деградацию, рост ресурсов.
Тестирование отказоустойчивости (Failover Testing)
Как система ведёт себя при отказе компонента. Проверяется переключение мастера, реплики, отказ ноды.
Тестирование восстановления (Recovery Testing)
Как быстро система восстанавливается после сбоя: время восстановления сервисов, очередей, индексов.
Стресс‑тестирование (Stress Testing)
Что произойдёт, если нагрузка превысит плановую. Находим предел прочности и точку деградации.
Объёмное тестирование (Volume Testing)
Как система работает при большом объёме данных. Проверяется деградация запросов при росте БД, файлов, очередей.
Тестирование масштабируемости (Scalability Testing)
Как система реагирует на увеличение нагрузки или ресурсов. Линейность роста RPS, потребление ресурсов.
Тестирование потенциальных возможностей (Capacity Testing)
Какое максимальное количество пользователей или RPS выдерживает система до деградации.
Конфигурационное тестирование (Configuration Testing)
Как различные конфигурации влияют на производительность. Проверка настроек ОС, БД, сервисов.
Тестирование сравнения (Comparison Testing)
Сравнение технологий, версий ПО или оборудования под одинаковой нагрузкой.
Подходы в нагрузке
Есть два основных подхода в нагрузке: первый — для имитации действий реального пользователя (клиента), второй — немудрёное закидывание однотипными запросами (подходит, к примеру, для изолированной нагрузки какого‑то из микросервисов).
Сценарный подход к нагрузке
Сценарный подход — когда пользователь ведёт себя как человек, а не как скрипт. Он переходит по страницам, думает, заполняет форму, ошибается, возвращается. Это сложнее моделировать, но даёт более реалистичную картину.
Без сценариев нагрузка — просто поток запросов. Но настоящая нагрузка — это путь пользователя, а не GET /products 10 раз в секунду.
Если у нас микросервисная архитектура, то при сценарном подходе мы имеем возможность наблюдать то, как сервисы отрабатывают запросы от клиентов и — как сервисы общаются между собой. Ну и как нам известно: если начинаются проблемы с межсервисным взаимодействием (например, один из них упал с ООМ), то клиент это тоже, скорее всего, почувсвует и будет крайне недоволен.
Hit‑based подход
Hit‑based подход — это «вколотим тысячу запросов в секунду и посмотрим, кто первый сдастся — API или балансировщик».
Подходит для систем, где важен именно throughput (пропускная способность), но плохо отражает реальное поведение пользователей. Полезно провести как раз тогда, когда хочется выяснить: какова реальная причина краша сервиса при межсервисном общении, если при приближенном к реальности сценарии не удаётся ясно установить проблему.
А где будем тестировать?
Можно оформить нагрузку на боевую систему, например, ночью, когда ожидается минимальное количество клиентов, но если что‑то сломается… Цель нагрузки будет скорее всего достигнута, однако есть нюансы… Вдруг не получится до вечера поднять систему, если случится некий FATAL.
Гораздо лучше всё делать без существенных потрясений. Оставим таки прод в покое и развернём отдельный стенд для тестов. Это, разумеется, стоит денег. И чаще всего — не малых. А всё потому что тестовый стенд должен быть максимально похож на прод. Быть его двойником. И это не рекомендация. Это аксиома.
Если тестируете на унылой ВМ, где всё — тяп‑ляп, то результаты можете сразу выбрасывать (ну или прикольнуться над начальством, предоставив им замечательные показатели, которые шокируют всех. Положительный эффект тоже будет: застявят раскатить нормальный стенд, соответствующий проду — ведь интересно же, как изменятся показатели при новых условиях. Обычно — становятся лучше).
Разница в CPU, RAM, редисе, даже в версии БД или объёме данных — всё это приводит к ложным выводам, что может сыграть в дальнейшем злую шутку после релиза.
И да! Кто‑то внимательный уже смог уловить, что нагрузку ОЧЕНЬ ЖЕЛАТЕЛЬНО проводить до релиза продукта.
ВАЖНО: Тестовый стенд ≈ прод!
На меньшее не соглашайтесь!
Пример плохого стенда:
Когда PROD: 32 CPU, 64 GB RAM, 4 ноды, кеш Redis
А тестовый «стенд»: дедовский ноутбук DevOps«а, с какой‑то раскатанной альфа‑версией продукта (»кстати, а когда мы её собирали?«)»
Итог: «На тесте всё летает, чудесно! А после релиза на проде почему‑то 5% ошибок и всё тормозит… Что же пошло не так?»
Профиль нагрузки
Если бы у вас была история браузера одного из клиентов, то захотелось бы вам посмотреть — чисто ради интереса — есть ли там что‑то интересненькое? Если вы решите заниматься нагрузкой, то хочешь‑не хочешь, а придётся узнать, где побывали пользователи в своих браузерах и клиентах приложений. В нагрузке этим мы занимаемся регулярно. Ничего личного — просто выполняем свою работу. И мы спокойно можем обратиться к истории посещений клиента (разумеется, посещений только нашего приложения), покопавшись в логах сервера/гейтвея тем или иным способом.
А зачем весь этот сталкинг? Не любопытсва ради! Мы выясняем поведение клиентов при взаимодействии с системой, составляем обобщённый профиль: профиль нагрузки.
Профиль нагрузки — распределение типов действий. К примеру, имеем онлайн‑магазин, проанализировав запросы из логов в самый горячий момент (пик посещений), мы видим такую картину: 55% запросов оказываются просмотром каталога, 30% — карточки товара, 10% — корзина, 4% — заказ, 1% — что‑то не особо важное. У нас есть распределение количества запросов, критичных для бизнеса (99%) и не очень (1%). Если критичные запросы мы будем обрабатывать долго или с ошибками, клиент может прийти в бешенство и вообще отказаться от пользования магазином. Да и знакомым всем расскажет, что вот у тех ребят ничего не работает. Денежный поток перекрывается. А это — страшный сон капиталиста с понедельника на вторник! Просыпаясь, он (капиталист‑бизнесмен) хватает трубку и звонит своему знакомому нагрузочному тестировщику, рассказывает про свой ночной кошмар и просит сделать так, чтобы этого никогда не произошло. Если деловое общение проходит гладко, то амбициозный предприниматель получает в свою команду хорошего сотрудника (за хорошие деньги, разумеется), который готов его подстраховать (и даже предсказывать будущее без всех этих снов с понедельника на вторник!).
Скилловый тестер наводит благодатную суету: достаёт аналитиков, девопсов, разрабов — вообще всех — и вытряхивает из них необходимые данные по максимуму (а иногда собирает их собственноручно, копаясь во всей инфре, логах и документации), а затем начинает предотвращение личного аппокалипсиса бизнесмена — свою работу, которую можно разбить на этапы:
определение целей (для подготовки МНТ);
анализ системы и требований (для подготовки МНТ… Снова эта абревиатура);
подготовка методики нагрузочного тестирования;
разработка нагрузочных скриптов;
подготовка тестовых данных;
настройка генератора нагрузки;
настройка мониторинга;
отладка тестов/предварительные запуски;
проведение тестирования;
анализ результатов и подготовка отчета.
Этапы тестирования
Составляем МНТ (Методику нагрузочного тестирования)
Снова это МНТ… А вот без этого документа — никуда. Вообще ничего не надо делать, пока не будет составлен хотя бы черновик (этим, кстати, нужно будет заниматься вам!) и согласован со всеми заинтересованными лицами документ, где всё будет разложено по полочкам: что мы собираемся делать, и зачем вот это всё. Этот документ — Методика Нагрузочного Тестирования (МНТ).
Не существует общепринятой формы этой доки, однако рекомендации, конечно же, есть.
Методика нагрузочного тестирования (МНТ)
Требования к документации:
дата составления
ФИО ответственного и согласовавших документ лиц (желательно иметь пруфы ещё)
Краткое описание тестируемого приложения, с указанием версии
Версии ОС/используемого ПО (тестовый контур) — дёргаем тов. DevOps«ов»
Архитектура системы — к ним же, можно позвать архитектора
-
Указать четкую цель/цели проведения тестирования
— ВЫ: «босс, а зачем нам это?»
-
Требования (если есть)
— БОСС: «Нет времени объяснять, я хочу, чтобы всё летало, и видеть иксы на счёте каждый день», — такое себе объяснение, конечно, придётся составлять требования самому. Но лучше всё‑таки выудить хотелки (throughput, responseTimes 90%‑line, 95%‑line и тд):
Инструменты — по душе
-
Описание метрик, получаемых в ходе тестирования
app‑side (throughput, responseTimes 90%‑line, 95%‑line и тд)
server‑side (CPU, Memory utilization и тд)
Описание модели нагрузки (операции и/или запросы, распределение)
План проведения тестирования
Цель теста
Описание профиля нагрузки
Метрики (что должны получить)
Критерии выхода из тестирования
при необходимости словарь терминов/определений и шаблон отчёта
Конечно, всё выше перечисленное — это прям в идеале. На практике чаще всего МНТ составлялось один раз 1000 назад, половина инфы уже далеко неактуальна, а вся нагрузка проводится по запросу корпоративных чатиках (кстати, допустимость этого тоже можно дописать в МНТ).
У такого подхода есть свои плсы и минусы. Познаётся на деле. Однако лучше таки поддерживать МНТ в актуальном состоянии, держа руку на пульсе проекта, чтобы к вам не было потом претензий: почему тут сделали так, а не этак, а босс хотел ещё вот это и так далее и тому подобное. Хотеть то можно многого, но мы уже заключили контракт, и этот контракт — МНТ.
Нагрузочные скрипты
Ну что, народ, погнали…
У нас есть дока, написанная нами и одобренная всеми. Теперь настало время творить! Пишем нагрузочные скрипты. Вы ведь в МНТ указали, как будете имитировать поведение пользователей? В таком случае ваш выбор сделан не случайно, и все думают, что вы знаете, что именно делаете (хотя в первые несколько дней, а то и недель — если проект большой и сложный с кучей микросервисов и прочих прелестей — может быть не совсем ясно, что делать — это норма). Глаза боятся — руки делают.
Выбираем инструмент по вкусу (JMeter, Locust, Gatling, k6, Performance Center и другие). Можно вообще самому написать асинхронный или мультитредовый код — изобретать велосипед, если времени много) и — за дело. Помните, это всего лишь инструмент, который помогает вам реализовать только часть большой работы. Но как раз эта часть очень важна, так как все результаты будут зависеть от того, насколько точно вы сумеете реализовать профиль/профили в виде сценария‑кода вашего генератора (некоторые генераторы предлагают создание сценариев нагрузки через GUI, но под капотом всё в том или ином виде переводится в код или конфиги).
Инструменты для генерации нагрузки
Вот примеры готовых для использования инструментов. Это наши молоты, которые вот‑вот обрушатся на лежащий на наковальне продукт. Выбирайте по душе, замахнитесь, сосредоточьтесь и не промахнитесь.
-
Locust (топ для Python‑щиков) — мой личный выбор Если бы Locust был человеком:
минимум понтов
максимум пользы
«давай я напишу тебе тест на 10к пользователей за 5 минут»
Простой пример: 1000 человек (виртуальных пользователей) одновременно логинятся и смотрят каталог на маркетплейсе, оформляя 200 RPS.
-
JMeter (GUI, Java, Kotlin — с версии 5.6)
Как Windows XP — работает, но хочется чего‑то поновее.
Сценарии создаются в олдовом GUI с возможностью скриптинга на Groovy, JS; создания jar модулей на Java/Kotlin.
Пример: Старые корпоративные сервисы, SOAP, JMS — вот там JMeter до сих пор живёт.
JMeter — мой первый инструмент. Почти универсален с различнымиплагинами по части протоколов, но вот по удобству — такоэ, что и стало причиной перехода на Locust.
-
Gatling (Scala, Java, Kotlin, JS)
Если хочешь прожечь сервер на 100к RPS — бери Gatling. Но изучать Scala ради этого — страдание.
Пробовал. Прикольно, но что‑то не то: много возни с конфигами, зависимостями и прочими прелестями JVM тусовки:D
и другие…
Подготовка тестовых данных
Ладно. Допустим, мы написали скрипты, всё здорово. Забрали токен авторизации, первично запустили в одного VUзера (виртуальный пользователь — единица нагрузки в генераторах). Только не привязывайтесь к ним. Они могут вас жестоко обмануть. Как и почему? Вопрос на размышление. Кто‑то может понять быстро, а кому‑то и пары месяцев окажется мало — таким ребятам лучше не связываться с нагрузкой), сценарий пробежал.
Здорово. Так, стоп. А БД‑то у нас пустая! Вот так на. Срочно созываем совет нужных спецов и говорим, что нам необходимо обфусцировать БД прода и копирнуть всё это дело на БД тестового стенда. Хорошо, если спецы говорят: «не вопрос, бро, ты там отдыхай, а мы на недельке всё оформим красиво… Только таску в Jira заведи, плиз». Но может быть и так: «уууххх… это займёт у нас… пока не могу сказать точно… там этсамое…», — настрой ясен...
Во втором случае — берём дело в свои руки. Смотрим, какие данные у нас есть на PRODe и оформляем их на тестовом — ручками. Можно написать скрипт генерации, можно использовать специализированные штуки (Mongo Compass, например) или оформить плотный вайб‑коддинг. В этом деле, думаю, вы разбираетесь сами.
В общем, нам нужно сделать так, чтобы наши БД были наполнены подобно продовским, а всеми необходимыми данными мы могли распоряжаться как нам необходимо для проведения правдоподобного теста. Обязательно проверяем логи сервисов на наличие ошибок после переноса: не должно быть каких‑то сообщений в духе поломанных связей, неприемлемых форматов и тому подобное. Делаем красиво!
Настройка генератора нагрузки и мониторинга
Почти готово! Что‑то запускается даже.
Блин, а как посмотреть, что вообще происходит?
Очень кстати внезапное сообщение от девопса: «бро, забыл сказать, у нас тут такая темка развёрнута: в Grafana куча бордов на любой вкус и цвет, все сервисы, зоопарк метрик appside/serverside — можешь брать, что захочешь! Если что‑то ещё нужно поднять и помониторить — дай знать, в таске Jira всё красиво распишем!».
Вот это подход! Моё уважение.
Но бывает и так, что ничего этого нет в помине. И скорее всего, организацией этого всего предстоит заниматься как раз вам! Печально, но ничего не поделаешь. Запрашиваем всюду доступы, обвешиваемся различными инструментами (прометей, графана, экспортеры всякие, ELKи, инфлаксы — вашем распоряжении много чего имеется) и возводим свой мониторинг с блэкджеком.
Подняли, проверили. Метрики идут, графики строятся, всё в цвете — красиво. Вроде систему мы видим насквозь! Отлично.
Хм…
Надо бы ещё сам генератор нагрузки настроить и замониторить…
Новое сообщение от девопса:
«Бро, я тут только что для тебя подготовил ноду в кубере. 96 CPU, 96 Gb RAM, лютый SSD, сеть пробросил до тестируемой системы, доступы выдал — всё в твоём распоряжении!».
Вот так подгон!
Всё правильно сделал этот таинственный девопс. Видимо, очень заинтересован в качественном тестировании. Он тоже знает, что нельзя позволить самому генератору нагрузки стать «узким местом» (bottleneck‑ом) да запороть весь тест, так и не узнав, на что действительно способна наша система.
Но, как вы уже поняли, иногда бывает, что этого таинственного скиллового девопса в организации может и не оказаться. Что делать в этом случае — вы прекрасно знаете!
Отладка, пробные запуски
Пришло время проверить, что вы там наворотили.
Пишем в чат: «Cейчас будет хана тестовому стенду. Если кто-то на нём что-то делает – лучше не надо! Уходите! Да и вообще, стенд мой! Почему вы тут оказались?».
Всех оповестили…
Что ж, пора! Ладно, на счёт тотального дестроя стенды мы пошутили, конечно. Устанавливаем количество виртуальных пользователей > 1 и наблюдаем, что запросы от генератора идут без ошибок, какие-то графики в графане побежали так, что стали отличаться от оных в состоянии простоя. Смотрим картинки интересующих нас сервисов – диаграммы, кривые линии какие-то появились. Вроде завелось.
Мы оказываем нагрузку на систему и видим, что она реагирует на это. Выглядит здорово, сложно не согласиться.
Но что это за буквы и цифры?
Основные метрики производительности
Кажется, это те самые метрики, о которых мы писали в МНТ.
Вот это уже серьёзно!
Нужно вспомнить… Открываем МНТ. Ага! Что-то интересное…
Метрики производительности можно разделить на APP-SIDE и SERVER-SIDE.
App-side метрики
Это метрики которые относятся к работе нашего тестируемого приложения. Рассмотрим их.
Времена ответов (response time). Это ключевая метрика производительности. Под временем ответа подразумевают время обработки запроса с момента его отправки клиентом до получения ответа. Чем меньше время ответа, тем пользователь довольнее. Время ответа это не константа и в массовой системе неизбежно будут нештатные ситуации и статистические выбросы. Для анализа статистических величин обычно используют их среднее значение, среднеквадратичное отклонение, но они не всегда правильно характеризуют полученные результаты. Более уместным является использование перцентилей.
-
90-й перцентиль времени доступа к данным — это такое значение времени доступа в мс., что при распределении времени доступа по возрастанию для всех принятых данных, 90% времени доступа попадает ниже этого значения. Для оценки обычно используют 50, 75, 90, 95 перцентили. Чем меньше разброс между этими величинами тем стабильней работает приложение.
Следует отличать времена ответов успешных запросов, от времен ответов ошибочных. Ответ при ошибочном запросе приходит быстро, банально из‑за потери соединения, и это может значительно влиять на статистику.
-
Пропускная способность (throughput) — характеристика емкости системы, а именно количество обрабатываемых запросов в единицу времени. Иногда эту величину требуют в виде «одновременно работающих пользователей». Зная интенсивность выполнения операций одним пользователем, можно определить их общее количество. Нам следует профессионально подходить к нагрузке, поэтому мы пользуемся метрикой RPS — запросами в секунду, а не абстрактными Vuser«ами. Виртуальные пользователи — один из элементов нашего нагрузочного инсрумента, которыми мы управляем подаваемым RPS‑ом в соответсвии с нашими сценариями и целями. Высокий RPS (при низком времени ответа) — много довольных реальных клиентов после релиза.»
Аналогичная метрика количество транзакций или бизнес‑операций в секунду. Под транзакцией или бизнес‑операцией понимается цепочка запросов которые составляют логически завершенное действие — операцию.
Процент ошибок. Под процентом ошибок или процентом невыполненных/проваленных запросов понимают отношение числа отказов в обработке запросов к общему количеству запросов в процентах, то есть число ответов с кодом, отличным от HTTP 200. Очевидно, что мало ошибок — это хорошо, много — плохо. А «много» — это сколько? Этот вопрос — на рассуждение ;-)
Server-side метрики
Эти метрики относятся к аппаратным ресурсам. Они характеризуют насколько «заполнены» наша сервера. Основные метрики утилизации:
центрального процессора (CPU usage,%)
оперативной памяти (Mem usage,%)
сетевых ресурсов (net)
ресурсов дисковой подсистемы (I/O wait)
Но также существуют и другие метрики, на которые стоит (а иногда и необходимо) уделять внимание, и которые могут быть «узким местом» вашей системы.
Например, количество:
свободного места на диске;
используемых файловых дескрипторов;
свободных сокетов;
серверов‑воркеров;
При выполнении различных видов нагрузочных тестов используют разные метрики. При тесте на поиск максимальной производительности необходимо следить за пропускной способностью, динамикой времен ответа, процентом ошибок и аппаратными метриками, ограничивающими нашу максимальную производительность.
При тестах на подтверждение максимальной производительности необходимо смотреть на пропускную способность, времена ответов, перцентили, процент ошибок, а также на аппаратные метрики для определения какой запас мощности у нас остается.
При выполнении теста на стабильность особое внимание следует уделять всевозможным «утечкам». Это увеличение потребления какого либо ресурса (CPU, MEM) при почти постоянной нагрузке.
В стресс тестировании особой специфической метрикой является время восстановления системы после задания критической нагрузки. Это позволяет проверить способность успешно восстанавливаться после сбоев сети, отказа оборудования или критических ошибок ПО.
Ну, ивкратце:
-
Что по CPU и памяти?
Выделенные ресурсы на проц умирают первыми (чаще всего). Любая тяжёлая операция масштабируется пропорционально количеству пользователей (росту RPS). Можем быстро добиться такого при стресс‑тесте, и не чуть медленнее при нагрузочном тестировании.
Память же умирает медленнее, зато эффектнее — OOM, краши и перезапуски сервиса. Large JSON responses, кеши, утечки и прочие последствия бездумного вайб‑кодинга — классические причины падений. Если у нас действительно есть проблема, то тестирование стабильности приведёт один из сервисов к такому состоянию (как думаете, на сколько по времени нужно запускать тест стабильности?)
CPU/RAM — ресурсы, на которых держится весь тест.
-
А по остальным метрикам?
RPS — пропускная способность. Как только падает при непрекращающеся нагрузке — мы на месте.
pct95 — показатель пользовательского опыта в реальности. У 5-ти процентов клиентов будет работать больше этого времени, но ничего страшного — потерпят. Мы ведь согласовали требования к времени ответа в МНТ?
pct99 — истина, от которой обычно пытаются отвернуться. Как думаете, почему так?
Error Rate — процент ошибок. Думаю, тут можно без комментариев. Кстати, кто‑нибудь уже подумал над вопросом, какой error rate можно считать высоким?
Проведение тестирования
Когда всё подготовлено — начинаются настоящие приключения. В этот момент нагрузочник становится человеком‑оркестром: запускает тесты, смотрит графаны, общается с девопсом, одновременно пьёт чай, потеет, ругается и пытается поймать момент, когда система начала «умирать».
Процесс проведения теста можно разделить на несколько этапов.
Контрольная проверка
Перед запуском теста необходимо убедиться, что:
тестируемая система в нормальном состоянии (все сервисы подняты, ресурсов достаточно);
мониторинг показывает корректные метрики (нет дропов данных, нет ошибок экспортеров);
генератор нагрузки готов: доступы есть, скрипты валидируются, RPS не прыгает;
тестовые данные доступны: БД наполнена, токены генерируются, очереди чистые.
Малейшая проблема на старте = сломанная вся серия тестов и зря проведённый рабочий день.
Прогрев (warm‑up)
Перед тем как давить на систему всей мощью, необходимо дать ей 5–15 минут, чтобы прогреться:
разогреть кэши;
заполнить connection pool;
прогреть JIT (если используется JVM);
разобраться с ленивыми инициализациями.
Прогрев — обязательная часть. Без него вы получите ложную деградацию, и все данные пойдут в мусор.
Основная фаза теста
Эта часть зависит от типа тестирования — максимум, стабильность, стресс, capacity… Но общие задачи одинаковы:
-
Что делает нагрузочник во время теста:
Следит за RPS, response time, error rate;
Смотрит на CPU / RAM сервисов;
Мониторит очереди, БД, Redis, Kafka, брокеры, внутренние API;
Фиксирует в таймлайне все аномалии;
Смотрит системные логи (ошибки, предупреждения);
-
Разгребает чат;
«ребят, кто на стенд залез?»;
«пожалуйста, отключите cron на этом сервисе»;
«девопсы, а это нормально, что у вас 2 реплики умерли?»;
Параллельно читает Хабр.
-
Во время теста важно:
не менять профиль нагрузки;
не править конфиги на лету;
не «перезапускать стенд, чтобы проверить одну гипотезу»;
не трогать БД, если только ты не хочешь потерять всё.
Фиксация ключевых событий
-
Любая аномалия — в протокол:
всплеск ошибок;
рост латентности;
деградация CPU;
увеличение memory leak;
перезапуск контейнера;
обрыв сетевого соединения;
изменение конфигурации стенда кем‑то со стороны (!).
Эти записи потом попадут в отчёт.
Пост‑нагрузочная стабилизация
После завершения основного теста:
дожидаемся снижения RPS;
-
смотрим признаки восстановления:
queue drain,
стабилизация CPU,
нормализация latency,
исчезновение ошибок из логов.
Если система не может восстановиться сама — это отдельный баг, который идёт в отчёт.
Сбор результатов
После теста мы должны собрать:
CSV/JSON статистику из инструмента нагрузки;
графики Grafana (скриншоты / экспорт в PNG/CSV);
логи сервисов;
системные метрики;
метрики брокеров/БД;
состояние очередей/кэшей;
дополнительные артефакты.
Всё это добро упаковываем в отчёт.
Составление отчёта
Отчёт — это не формальность. Это документ, который читают:
менеджеры,
разработчики,
архитекторы,
DevOps,
иногда даже директор (если всё сломалось сильно).
Отчёт должен быть:
понятным;
честным;
кратким;
структурированным.
Он отвечает на один вопрос:
«Выдержит ли наша система нагрузку, которую мы ждём?»
Структура идеального отчёта
-
Введение
Что тестировали, зачем, в каких условиях. На одну страницу.
-
Описание стенда
Детально:
CPU/RAM каждого сервиса,
версии ПО,
конфиги,
схемы кешей,
настройки БД,
реплики,
connection‑pool.
Если стенд слабее прода, об этом пишем жирным шрифтом.
-
Модель нагрузки
Чётко и прозрачно:
какие сценарии;
распределение операций (профиль нагрузки);
RPS / concurrency (VUзеры);
паузы, pacing;
размеры данных (тела запросов).
-
Ход тестирования
Хронология:
время запуска теста;
прогрев;
основные события;
аномалии;
поведение системы.
Тут же: ссылки на графики.
-
Результаты App‑Side
В таблицах:
pct50 / pct75 / pct90 / pct95 / pct99;
средние времена;
пропускная способность (RPS);
error rate;
распределение ошибок по кодам;
графики latency.
-
Результаты Server‑Side
CPU, RAM, сеть, диски, очереди, connection pool, GC (если есть). Графики — обязательны.
-
Bottlenecks (узкие места тестируемой системы)
Чётко пояснить:
какой сервис упёрся в CPU;
какая БД дала рост latency;
какая очередь раздувалась;
почему errors > 0,5%;
почему pct95 вырос вдвое.
-
Выводы по тесту
Коротко, по делу, без воды:
тест пройден / не пройден;
текущие лимиты RPS;
рекомендуемая нагрузка;
прогноз будущего роста.
-
Рекомендации
Вот это обычно читают особенно внимательно!
Например:
увеличить CPU на сервис X;
настроить connection pool;
починить утечку памяти;
оптимизировать SQL‑запрос;
добавить реплику БД;
внедрить кэширование;
рефакторинг кода функций, дающих просадку.
-
Приложения
Понятные артефакты:
таблицы метрик;
CSV из Locust/JMeter;
скриншоты графиков;
ошибки из логов;
конфиги теста.
Что нужно для проведения нагрузочного тестирования?
Чтобы не искать по чатам и не выпрашивать доступы, вот детальный перечень всего необходимого.
1. Инфраструктура
Тестовый стенд максимально похожий на прод (CPU, RAM, кластеры, очереди, кеши, БД, конфиги)
CI/CD для отката версий (не шутка — пригодится, ОЧЕНЬ)
Изолированная сеть для генератора нагрузки с доступностью к тестируемой системе
2. Мониторинг
Must‑have инструменты:
Prometheus — сбор метрик (системные метрики: CPU, RAM, I/O, FD, network)
Grafana — визуализация метрик
Elastic / Kibana / Graylog / Loki — сбор логов
Node Exporter — сбор системных метрик
-
Экспортеры БД:
Mongo Exporter — сбор метрик MongoDB
Postgres Exporter — сбор метрик PostgreSQL
Redis Exporter — сбор метрик Redis
Kafka Exporter — сбор метрик Kafka
Rabbit Exporter — сбор метрик RabbitMQ
3. Генератор нагрузки
-
Locust, JMeter, Gatling, k6 и пр. (выбрать что‑то одно):
-
Отдельная машина / нода:
много CPU,
хорошая сеть,
SSD (если логов много),
32–128 GB RAM (по ситуации)
-
4. Доступы и учётки
к сервисам;
к логам;
к Grafana;
к Prometheus;
в Kubernetes / Docker;
к БД;
к API gateway;
к VPN (если закрытый контур).
5. Тестовые данные
Размеры данных должны быть приближены к реальным.
база, похожая на прод (обфусцированная);
пользователи и токены;
товары/объекты/документы (в зависимости от сервиса);
тестовые очереди.
6. Документация
методика нагрузочного тестирования (МНТ);
профиль нагрузки и сценарии;
схемы архитектуры;
SLA и требования по перцентилям;
лимиты ресурсов.
7. Набор артефактов для отчёта
результаты генератора (CSV/JSON/HTML);
экспорт графиков;
логи;
системные метрики;
фиксация узких мест.
Финальное слово
«Я точно знаю, сколько нужно RPS, чтобы поставить твою систему на колени…»
Ну ладно! ?
А если по факту:
Быть тестером производительности — это не просто писать скриптики и жать кнопку «Запуск», но БЫТЬ и прогером, и девопсом, аналитиком и, конечно же, тестером, используя на максимум все доступные инструменты вместе с собственными знаниями (куда же без них).