Блог Stepik про учебу и карьеру

Виды тестирования производительности: чем отличаются load, stress, spike, soak и chaos testing

Программирование
Тестирование производительности — это не только проверка того, сколько пользователей выдерживает система. Можно запустить нагрузку, получить графики с latency, RPS и ошибками, но так и не понять, что именно пошло не так: система не справляется с обычной нагрузкой, не выдерживает резкий всплеск трафика, начинает деградировать спустя несколько часов или не умеет корректно переживать отказ отдельного компонента.

О том, как выбрать подходящий вид тестирования производительности и что именно можно проверить с помощью load, stress, spike, soak, scalability, resilience и chaos testing, рассказывает Никита Филонов — автор курса «Нагрузочное тестирование на Python» на Stepik. В статье он разбирает основные виды performance testing, объясняет, какие задачи решает каждый из них и как интерпретировать результаты тестов.
Когда говорят про тестирование производительности, чаще всего имеют в виду нагрузочное тестирование. Но на практике существует несколько типов performance testing, и каждый из них отвечает на свой вопрос: выдерживает ли система ожидаемую нагрузку, где находится её предел, что происходит при резком всплеске трафика или длительной работе.

Поэтому сначала важно определить, что именно мы хотим проверить, а уже потом выбирать тип теста. Один сценарий не может ответить на все вопросы сразу.

Разберём основные виды тестирования производительности и выясним, что именно они проверяют, когда нужны и почему нельзя просто заменить один другим.

Load testing: проверка ожидаемой нагрузки

Load testing — это классическое нагрузочное тестирование. Его задача — проверить, как система ведёт себя при ожидаемой рабочей нагрузке.

Например, вы знаете, что в пике сервисом будут пользоваться 300–500 одновременных пользователей. Или ожидаете 200 RPS на конкретный API. Вопрос простой: выдержит ли система эту нагрузку стабильно?

Здесь важно слово «ожидаемой». Load testing не нужен для того, чтобы во что бы то ни стало сломать систему. Он нужен, чтобы проверить нормальный рабочий сценарий до того, как с ним столкнутся реальные пользователи.
Во время такого теста обычно смотрят:

  • время отклика;
  • RPS / throughput;
  • процент ошибок;
  • CPU;
  • память;
  • сеть;
  • состояние базы данных, очередей и внешних зависимостей.
Но сама нагрузка должна быть похожа на реальную. Пользователь не делает один и тот же запрос бесконечно без паузы. У него есть сценарий: открыть страницу, авторизоваться, посмотреть данные, выполнить действие, подождать, перейти дальше.

Если тест никак не похож на реальное поведение пользователей, выводы будут слабыми.
Типичный кейс для load testing — проверка перед релизом. Например, команда изменила API, добавила новый функционал или ожидает рост трафика. Тест помогает понять, выдержит ли система штатную нагрузку без роста latency, ошибок и упора в ресурсы.

Главная ошибка — путать load testing со stress testing. Если вы сразу дали системе нагрузку сильно выше нормы, а потом она упала, это ещё не значит, что она плохо работает при ожидаемой нагрузке. Вы проверяли уже другой сценарий.

Stress testing: поиск предела системы

Stress testing отвечает на другой вопрос: что будет, если нагрузка станет выше нормы?

Если load testing проверяет рабочий режим, то stress testing проверяет границу. Где система начинает деградировать? Какой компонент ломается первым? Что происходит после превышения лимита? Система восстанавливается сама или остаётся в плохом состоянии?
Например, вы знаете, что сервис стабильно выдерживает 300 пользователей. Дальше начинаете повышать нагрузку: 500, 800, 1000, 1500. В какой-то момент начинают расти задержки, появляются ошибки, забиваются connection pool, очередь, база или внешний сервис.

Это и есть полезная информация.
Stress testing нужен не только для того, чтобы сказать «система упала». Гораздо важнее понять, как именно она падает.

Один вариант — система деградирует плавно: latency растёт, часть запросов начинает отваливаться, но основные функции ещё работают. Другой вариант — резкий обвал: один компонент перестал отвечать, за ним начали падать остальные сервисы, пошёл каскадный сбой.
Это разные ситуации и разные инженерные выводы.

Stress testing полезен перед крупными акциями, распродажами, маркетинговыми кампаниями, миграциями и изменениями архитектуры. Он помогает понять запас прочности и найти узкие места заранее.

Проводить такой тест нужно аккуратно. Он специально выводит систему за нормальные пределы, поэтому для продакшена это рискованный сценарий. Чаще его проводят на отдельном стенде, который максимально близок к боевому окружению.

Spike testing: проверка резкого всплеска

Spike testing проверяет не просто большую нагрузку, а резкий скачок.

Это важное отличие.

Stress testing часто наращивает нагрузку постепенно. Spike testing моделирует ситуацию, когда трафик вырос почти мгновенно. Например, было 200 RPS, а через несколько секунд стало 3000 RPS.

Такое бывает при распродажах, пуш-уведомлениях, вирусном трафике, ошибках в клиентском приложении или внешних событиях, которые резко приводят пользователей в систему.

В spike testing важно смотреть не только на сам пик, но и на поведение после него.

Система может пережить одну минуту высокой нагрузки, но потом ещё двадцать минут разгребать очередь, держать высокий latency или продолжать отдавать ошибки. С точки зрения пользователя это всё ещё проблема.
Во время spike testing проверяют:

  • выдерживает ли система резкий вход в пик;
  • успевает ли сработать автоскейлинг;
  • не ломается ли балансировщик;
  • не забиваются ли очереди;
  • не отваливаются ли зависимости;
  • как быстро система возвращается в нормальное состояние.
Типичная ошибка — считать spike testing разновидностью stress testing. Но вопросы разные.
Stress testing отвечает: где предел системы?
Spike testing отвечает: что будет, если нагрузка ударит резко?
В распределённых системах это могут быть два совершенно разных результата. Система может выдерживать постепенный рост, но плохо переживать резкий скачок, потому что инфраструктура не успевает адаптироваться.

Soak testing: проверка на длинной дистанции

Иногда система отлично проходит обычный нагрузочный тест. 15–30 минут всё хорошо: latency нормальный, ошибок почти нет, ресурсы выглядят спокойно.

А через несколько часов начинаются проблемы.

Память медленно растёт. Соединения не возвращаются в пул. Очередь постепенно накапливает лаг. Время отклика ухудшается. Фоновые процессы начинают мешать основным сценариям.

Именно это проверяет soak testing, или endurance testing.

Его задача — посмотреть, как система ведёт себя под нагрузкой долго. Здесь важна не экстремальная интенсивность, а продолжительность.

Нагрузка может быть обычной, как в load testing. Но тест идёт не 15 минут, а несколько часов, ночь, сутки или дольше.
Soak testing помогает находить накопительные проблемы:

  • утечки памяти;
  • утечки соединений;
  • рост latency со временем;
  • деградацию кешей;
  • накопление лага в очередях;
  • проблемы с файловыми дескрипторами;
  • влияние фоновых задач;
  • проблемы сборщика мусора.
Главная особенность таких дефектов в том, что они не видны на коротком прогоне. Система не падает сразу. Она постепенно теряет нормальное состояние.

Такой тип тестирования особенно важен для backend-сервисов, банковских систем, телеком-продуктов, интеграционных платформ и любых сервисов, которые должны работать долго без ручного перезапуска.

Типичная ошибка — ограничиться коротким load testing и решить, что система стабильна. Короткий тест отвечает на вопрос: «работает ли система сейчас?»

Soak testing отвечает на другой вопрос: «не начнёт ли система разваливаться через несколько часов такой же работы?»

Scalability testing: проверка масштабирования

Scalability testing нужен, чтобы понять, помогает ли системе добавление ресурсов.
Например, сервис держит 100 RPS. Вы добавляете ещё один инстанс и ожидаете, что он начнёт держать 200 RPS. Но на практике может получиться иначе.

Вариант первый: стало 180 RPS. Масштабирование работает, но есть накладные расходы.

Вариант второй: стало 110 RPS. Значит, узкое место не в количестве инстансов.

Вариант третий: latency вырос, ошибок стало больше, база упёрлась в лимиты. Значит, приложение масштабировали, а зависимость — нет.
Scalability testing проверяет, как меняется производительность при изменении ресурсов и конфигурации:

  • больше CPU;
  • больше памяти;
  • больше инстансов;
  • другой размер пула соединений;
  • другая конфигурация базы;
  • другой объём данных.
Здесь важно не просто «дать больше нагрузки», а сравнить несколько состояний системы. Например: один инстанс, два инстанса, четыре инстанса. После этого можно увидеть, растёт ли throughput, как меняется latency и где появляется новое узкое место.

Основная ошибка — ожидать линейного роста. В реальности добавление ресурсов почти никогда не даёт идеальный прирост. Если ресурсов стало в два раза больше, это не значит, что производительность тоже вырастет ровно в два раза.

Scalability testing нужен, чтобы не решать проблемы вслепую. Иногда команда пытается «залить проблему железом», но производительность почти не меняется, потому что ограничение находится в базе данных, синхронной интеграции, блокировках, очередях или архитектуре.

Resilience testing: проверка отказоустойчивости

Resilience testing проверяет, что будет с системой при сбоях.

Падает база. Отваливается внешний API. Пропадает сеть между сервисами. Один инстанс перестаёт отвечать. Очередь начинает работать медленнее. Зависимость возвращает ошибки.

Вопрос не в том, случится ли такой сбой, а в том, насколько болезненным он будет.
Во время resilience testing проверяют:

  • продолжает ли система работать частично;
  • корректно ли обрабатываются ошибки;
  • срабатывают ли retry;
  • нет ли бесконечных повторов;
  • нет ли каскадного сбоя;
  • происходит ли переключение на резерв;
  • восстанавливается ли система после возвращения зависимости.
Простой пример — сервис A ходит в сервис B. Сервис B начинает тормозить или отвечать ошибками. Если сервис A продолжает бесконечно слать запросы, он может сам начать деградировать: потоки заняты, очереди растут, ресурсы заканчиваются.

Для таких сценариев используют механизмы вроде circuit breaker. Если зависимость нестабильна, система временно перестаёт отправлять туда запросы и быстро возвращает ошибку, fallback или данные из кеша. Это помогает не усилить проблему и не превратить локальный сбой в каскадный.

Resilience testing особенно важен для микросервисов, платёжных систем, банковских продуктов и любых систем с большим количеством внешних зависимостей.

Типичная ошибка — думать, что отказоустойчивость появляется сама по себе, если есть несколько инстансов или репликация. На практике без проверки система часто ведёт себя неожиданно: не переключается, зацикливается в retry, продолжает бить падающую зависимость или остаётся в деградированном состоянии после восстановления.

Chaos testing: контролируемое внесение сбоев

Chaos testing — это более зрелый уровень проверки устойчивости.

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

Но важно не путать chaos testing с «давайте что-нибудь сломаем».

Нормальное хаос-тестирование — это контролируемый эксперимент. У него есть гипотеза, ограничения, наблюдаемость, план восстановления и понятные критерии остановки.
Перед chaos testing у команды уже должны быть:

  • мониторинг;
  • алерты;
  • логи и трассировка;
  • понятные SLO/SLA;
  • механизмы rollback;
  • понимание нормального поведения системы;
  • базовые load и resilience тесты.

Если всего этого нет, хаос-тестирование превращается не в инженерную практику, а в способ устроить пожар.
Chaos testing имеет смысл в зрелых распределённых системах, где простой стоит дорого, а инфраструктура уже умеет автоматически восстанавливаться. Для небольшого проекта начинать с chaos testing обычно бессмысленно. Сначала нужно научиться стабильно проводить обычные нагрузочные тесты, понимать метрики и проверять конкретные сценарии отказа.

Как выбрать нужный тип теста

Самый простой способ — начать с вопроса, который вы хотите проверить.
Цель
Тип теста
понять, выдержит ли система ожидаемую рабочую нагрузку
load testing
найти предел и посмотреть поведение за пределом нормы
stress testing
проверить резкий скачок трафика
spike testing
понять, не деградирует ли система за несколько часов работы
soak testing
проверить, помогает ли добавление ресурсов
scalability testing
понять поведение при отказе зависимости
resilience testing
проверить устойчивость зрелой системы к непредсказуемым сбоям
chaos testing
Главное — не смешивать всё в один тест. Один сценарий не ответит на все вопросы сразу.

Можно провести тест на 1000 пользователей, получить красивые графики и всё равно не понять, что именно проверялось: штатная нагрузка, предел системы, всплеск, масштабирование или отказоустойчивость.

Итог

Тестирование производительности начинается не с выбора инструмента и не с количества виртуальных пользователей. Оно начинается с цели: что именно нужно проверить?

Стабильную работу под ожидаемой нагрузкой? Предел системы? Резкий пик? Долгую работу? Масштабирование? Поведение при сбое?

От ответа зависит тип теста, профиль нагрузки, длительность, метрики и выводы.

Если выбрать тип тестирования неправильно, можно получить графики, но не получить инженерного результата. А хороший performance testing должен отвечать на конкретный вопрос и помогать принять решение: релизить, оптимизировать, масштабировать, менять архитектуру или дорабатывать отказоустойчивость.

Если хотите разобраться в нагрузочном тестировании на практике, проходите курс автора статьи Никиты Филонова на Stepik – «Нагрузочное тестирование на Python»

В курсе разбирается не только запуск нагрузки, но и инженерный подход: как выбирать профиль, писать сценарии, смотреть на метрики, анализировать результаты и понимать, что происходит с системой под нагрузкой.

Это хороший следующий шаг, если хочется не просто знать термины load, stress и spike testing, а научиться применять нагрузочное тестирование в реальных задачах.