Одним из критически важных этапов разработки веб-приложений является нагрузочное тестирование. Этот процесс необходим для выявления потенциальных узких мест в системе, а также для обеспечения того, что приложение способно выдерживать предполагаемое количество пользователей и запросов без ухудшения производительности.
Введение в нагрузочное тестирование
Нагрузочное тестирование представляет собой процесс имитации различных уровней пользовательской активности с целью оценки производительности веб-приложения. Основная задача такого тестирования — определить, насколько эффективно система справляется с возрастающим трафиком и где находятся ее пределы. В процессе нагрузочного тестирования выявляются критические точки отказа и оценивается максимальная пропускная способность приложения.
Основные методики нагрузочного тестирования
Пиковая нагрузка (Spike Testing): Данный метод фокусируется на оценке поведения системы при резком увеличении нагрузки. Он позволяет определить, насколько стабильно приложение работает при внезапных всплесках пользовательской активности.
Длительное тестирование (Soak Testing): Этот метод используется для проверки устойчивости системы при стабильной нагрузке на протяжении продолжительного времени. Он помогает выявить долгосрочные проблемы, такие как утечки памяти или сбои в работе базы данных.
Стресс-тестирование (Stress Testing): Этот тип тестирования оценивает производительность системы при нагрузке, превышающей ожидаемую. Цель состоит в том, чтобы определить точку, при которой приложение начинает сбоить, и как быстро оно восстанавливается после перегрузки.
Постепенное увеличение нагрузки (Ramp-Up Testing): В рамках этой методики нагрузка на систему увеличивается постепенно до достижения определенного уровня. Это позволяет выявить пороговые значения, при которых начинаются проблемы с производительностью.
Инструменты для нагрузочного тестирования Java веб-приложений
Для эффективного нагрузочного тестирования Java веб-приложений существует множество инструментов, каждый из которых обладает своими особенностями и преимуществами. Ниже представлены наиболее востребованные из них:
Apache JMeter: Один из наиболее популярных инструментов для проведения нагрузочного тестирования, поддерживающий различные протоколы, включая HTTP, HTTPS, SOAP и JDBC. JMeter предоставляет широкий функционал для создания сложных тестовых сценариев и последующего анализа результатов. Универсальность и мощные аналитические возможности делают его предпочтительным решением для нагрузочного тестирования веб-приложений.
# Пример запуска теста в JMeter
jmeter -n -t test_plan.jmx -l results.jtl -e -o /path/to/output/folder
Gatling: Этот инструмент, разработанный на языке Scala, известен своей высокой производительностью и возможностью масштабирования тестов. Gatling предлагает удобный DSL (Domain-Specific Language) для создания сценариев тестирования и обладает мощными средствами анализа, что делает его идеальным для проведения сложных и ресурсоемких нагрузочных тестов.
class BasicSimulation extends Simulation {
val httpProtocol = http.baseUrl("https://localhost:8080")
val scn = scenario("Basic Scenario")
.exec(http("request_1").get("/"))
setUp(scn.inject(atOnceUsers(1000)).protocols(httpProtocol))
}
Locust: Инструмент для нагрузочного тестирования, написанный на Python. Locust позволяет разрабатывать тестовые сценарии на языке Python, что делает его особенно привлекательным для разработчиков, уже знакомых с этим языком. Он легко интегрируется с другими системами и предлагает гибкие возможности управления нагрузкой, что делает его подходящим для различных типов проектов.
from locust import HttpUser, TaskSet, task
class UserBehavior(TaskSet):
@task
def index(self):
self.client.get("/")
class WebsiteUser(HttpUser):
tasks = [UserBehavior]
min_wait = 5000
max_wait = 9000
Apache Benchmark (ab): Это легковесный инструмент, предназначенный для быстрого выполнения базовых тестов производительности веб-серверов. Apache Benchmark отличается простотой использования и подходит для быстрой оценки производительности веб-приложений в условиях базовой нагрузки. Однако, его функционал ограничен, и он не предназначен для выполнения сложных сценариев тестирования.
# Пример запуска теста с 1000 запросами и 100 параллельными пользователями
ab -n 1000 -c 100 http://localhost:8080/
Пример нагрузочного тестирования с использованием Apache JMeter
Ниже приводится подробный пример выполнения нагрузочного тестирования Java веб-приложения с использованием Apache JMeter. Этот пример охватывает все ключевые этапы: от установки JMeter до анализа результатов тестирования.
Установка Apache JMeter
-
Загрузка и установка: Загрузите последнюю версию Apache JMeter с официального сайта.
-
Запуск JMeter: После установки запустите JMeter с помощью команды
jmeter
в командной строке.
Создание тестового плана
-
Создание нового тестового плана: Откройте JMeter и создайте новый тестовый план.
-
Добавление группы потоков (Thread Group): Группа потоков определяет количество пользователей, время разгона (Ramp-Up) и количество циклов выполнения теста.
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setName("Example Thread Group");
threadGroup.setNumThreads(100); // Указание числа пользователей (потоков)
threadGroup.setRampUp(10); // Время разгона в секундах
threadGroup.setLoopCount(1); // Количество циклов
Добавление элементов к тестовому плану
HTTP Request Sampler: Добавьте HTTP Request Sampler для задания HTTP-запросов к тестируемому веб-приложению. Укажите домен, порт, путь и метод запроса.
HTTPSampler httpSampler = new HTTPSampler();
httpSampler.setDomain("example.com");
httpSampler.setPort(80);
httpSampler.setPath("/api/test");
httpSampler.setMethod("GET");
Конфигурация тестового плана: Добавьте настроенную группу потоков и HTTP Request Sampler в тестовый план.
TestPlan testPlan = new TestPlan("Example Test Plan");
testPlan.addThreadGroup(threadGroup);
threadGroup.addSampler(httpSampler);
Добавление слушателей для анализа результатов
View Results Tree: Этот элемент позволяет визуализировать результаты выполнения каждого запроса в виде дерева.
ViewResultsTree resultsTree = new ViewResultsTree();
testPlan.add(resultsTree);
Summary Report: Предоставляет сводные статистические данные о результатах тестирования.
SummaryReport summaryReport = new SummaryReport();
testPlan.add(summaryReport);
Запуск теста и анализ результатов
Запуск теста: Настройте и запустите тестовый план с помощью движка JMeter.
JMeterEngine jmeterEngine = new StandardJMeterEngine();
jmeterEngine.configure(testPlan);
jmeterEngine.run();
Анализ результатов: После завершения теста проанализируйте результаты для выявления узких мест и потенциальных точек отказа.
for (SampleResult result : resultsTree.getResults()) {
System.out.println("Response time: " + result.getTime()); // Время ответа
System.out.println("Response code: " + result.getResponseCode()); // Код ответа сервера
}
Этот пример демонстрирует, как можно использовать Apache JMeter для создания и выполнения нагрузочного тестирования веб-приложений на Java, а также для анализа результатов тестирования с целью улучшения производительности и надежности системы.
Преобразование нагрузки в RPS (Запросы в секунду) в Apache JMeter
Когда нагрузка на систему должна выражаться в запросах в секунду (RPS) вместо количества пользователей, подход к настройке тестового плана в Apache JMeter требует некоторых изменений. Это особенно полезно, когда нагрузка на различные адреса может отличаться при параллельном выполнении запросов. Рассмотрим пошаговую инструкцию по настройке такого теста.
Шаг 1: Настройка переменной load_msg_sec
-
Добавление переменной в тестовый план:
-
Кликните на корневой элемент тестового плана в JMeter.
-
Добавьте новую переменную с именем
load_msg_sec
. Название переменной можно выбрать любое, но для ясности будем использоватьload_msg_sec
.
-
-
Установка значения переменной:
-
В значении переменной можно указать как константное значение, так и параметризованное. Для параметризованного значения в столбце
Value
введите следующее:
-
${__P(load, 50)}
Здесь load
— это название параметра, а 50
— значение по умолчанию, если параметр не передан.
Шаг 2: Добавление Constant Throughput Timer
-
Добавление таймера:
-
Перейдите в вашу группу потоков (Thread Group).
-
Добавьте
Constant Throughput Timer
:RBM
→Add
→Timer
→Constant Throughput Timer
.
-
-
Настройка таймера:
-
В поле
Target throughput (in samples per minute)
укажите следующую формулу:
-
${__jexl3(${load_msg_sec} * 60 * #percent#)}
Здесь:
-
${load_msg_sec}
— количество запросов в секунду, определённое переменнойload_msg_sec
. -
60
— коэффициент для перевода запросов в секунду в запросы в минуту (так как JMeter ожидает значения в запросах в минуту). -
#percent#
— процент от общего количества запросов, который будет применяться при параллельном тестировании нескольких адресов. Этот параметр определяется согласно методике нагрузочного тестирования.
Шаг 3: Настройка Basic Authentication
При тестировании на стендах, защищённых базовой аутентификацией (Basic Auth), необходимо настроить корректную отправку заголовка авторизации, чтобы избежать ошибок 403.
-
Добавление
BeanShell PreProcessor
:-
Кликните на вашу группу потоков (Thread Group).
-
Добавьте
BeanShell PreProcessor
:RBM
→Add
→Pre Processors
→BeanShell PreProcessor
. -
Вставьте следующий код в
BeanShell PreProcessor
:
import org.apache.commons.codec.binary.Base64; byte[] encodedUsernamePassword = Base64.encodeBase64("login:password".getBytes()); vars.put("base64HeaderValue", new String(encodedUsernamePassword));
-
Здесь
"login:password"
замените на реальные данные для аутентификации.
-
-
Добавление
HTTP Header Manager
:-
В той же группе потоков добавьте
HTTP Header Manager
. -
Добавьте следующий заголовок:
-
Name
:Authorization
-
Value
:Basic ${base64HeaderValue}
-
-
Переменная
${base64HeaderValue}
, используемая в значении заголовка, была установлена вBeanShell PreProcessor
.
-
Лучшие практики нагрузочного тестирования
-
Реалистичные сценарии: Тестовые сценарии должны максимально приближаться к реальным условиям эксплуатации приложения. Это позволяет точно моделировать нагрузки и предсказывать поведение системы, выявляя потенциальные проблемы до того, как они появятся в реальной эксплуатации.
-
Мониторинг и анализ: Эффективное нагрузочное тестирование требует тщательного мониторинга системных ресурсов и анализа полученных данных. Использование специализированных инструментов позволяет оперативно выявлять узкие места и принимать меры для их устранения, тем самым оптимизируя производительность системы.
-
Регулярность тестирования: Постоянное проведение нагрузочных тестов необходимо для своевременного выявления проблем, особенно после внесения изменений в код или инфраструктуру. Регулярное тестирование помогает поддерживать высокую стабильность и производительность приложения.
-
Интеграция с CI/CD: Включение нагрузочного тестирования в процессы непрерывной интеграции и доставки (CI/CD) обеспечивает автоматический контроль производительности после каждого изменения кода. Это позволяет минимизировать риск появления проблем с производительностью в продакшене.
-
Комбинирование инструментов: Использование различных инструментов для нагрузочного тестирования (например, Apache JMeter, Gatling, Locust) помогает получить всесторонний обзор производительности приложения. Это позволяет выявлять разные аспекты поведения системы под нагрузкой и разрабатывать более комплексные решения для их оптимизации.
-
Многоуровневое тестирование: Проведение тестов при различных уровнях нагрузки — от минимальной до экстремальной — позволяет глубже понять поведение приложения и определить его пределы. Это помогает выявить, как система реагирует на разные сценарии нагрузки и где могут возникнуть проблемы.
-
Документирование и отчеты: Ведение подробной документации и создание отчетов по результатам тестирования важны для анализа и последующего улучшения системы. Это позволяет отслеживать тенденции, делать обоснованные выводы и планировать дальнейшие шаги по оптимизации.
-
Оптимизация и настройка: Результаты нагрузочного тестирования должны быть использованы для оптимизации системы. Это может включать настройку серверов, оптимизацию запросов к базе данных, улучшение алгоритмов и другие меры, направленные на повышение производительности приложения.
-
Сотрудничество с командой: Эффективное тестирование требует тесного взаимодействия с разработчиками и другими заинтересованными сторонами. Совместная работа позволяет быстро реагировать на обнаруженные проблемы и вносить улучшения в продукт.
Пример протокола нагрузочного тестирования веб-приложения
Документ описывает результаты проведения нагрузочного тестирования системы.
1. Объект испытаний
Объектом испытаний является веб-приложение, которое подвергалось нагрузочному тестированию с целью оценки его производительности и стабильности при различных уровнях нагрузки.
2. Цели испытаний
-
Проверка соответствия разработанной системы предъявляемым требованиям.
-
Определение максимальной и пиковой производительности системы.
-
Проверка стабильности работы системы в течение длительного времени под нагрузкой.
3. Базовый профиль
Базовый профиль тестирования включает в себя следующие параметры, рассчитанные на основе требований к производительности и предполагаемого пользовательского поведения:
Код |
Требование |
Значение |
---|---|---|
1 |
Общее количество запросов к системе в месяц |
30 000 000 |
2 |
Пиковое количество запросов в месяц |
3 300 000 |
3 |
Пиковое количество запросов в неделю |
900 000 |
4 |
Пиковое количество запросов в день |
110 000 |
5 |
Количество пользователей в месяц |
300 000 |
6 |
Количество пользователей в неделю |
60 000 |
7 |
Количество пользователей в день |
10 000 |
Расчетное количество запросов в час на основе максимального количества запросов:
На основе Customer Journey Map (CJM) выделены объекты, создающие основную нагрузку:
Объект |
URI |
Процент запросов в час |
Количество запросов в час |
---|---|---|---|
Объект 1 |
/ |
27% |
11 340 |
Объект 2 |
/…/ |
15% |
6 300 |
Объект 3 |
/…/ |
11% |
4 620 |
Объект 4 |
/…/ |
5% |
2 100 |
Объект 5 |
/…/ |
16% |
6 720 |
Объект 6 |
/…/ |
5% |
2 100 |
Объект 7 |
/…/ |
6% |
2 520 |
Объект 8 |
/…/ |
15% |
6 300 |
Нагрузку на объекты распределили пропорционально целевой аудитории. Запросы распределяются равномерно в течение часа:
4. План тестирования
-
Разработка профиля нагрузочного тестирования.
-
Настройка систем мониторинга для отслеживания производительности.
-
Разработка скриптов генерации нагрузки.
-
Подготовка тестовых данных (например, варианты значений для поисковых запросов) и создание скриптов для их загрузки в базу данных перед тестированием и очистки после.
-
Проведение нагрузочных тестов.
-
Анализ результатов нагрузочного тестирования.
5. Типы проводимых тестов
Поиск пиковой производительности
-
Нагрузка: ступенчатая.
-
Начальная нагрузка: 40% от базового профиля.
-
Шаг: увеличение на 30% от базового профиля.
-
Продолжительность ступени: 30 минут или до отказа системы.
-
Критерий завершения теста: отказ системы.
-
Критерий успешности: максимальная производительность системы превышает значения базового профиля.
Проверка стабильности работы системы
-
Нагрузка: равномерная с плавным разгоном.
-
Максимальная нагрузка: базовый профиль.
-
Время разгона: 15 минут.
-
Длительность основного этапа: 4 часа.
-
Критерий завершения теста: истечение времени или отказ системы.
-
Критерий успешности: завершение теста по истечении времени без отказов системы.
ребования к производительности системы
1. Утилизация ресурсов во время тестов
Для достижения устойчивой производительности и стабильности системы под нагрузкой утилизация ресурсов сервера во время тестирования должна соответствовать следующим показателям:
-
Утилизация CPU: не более 80%.
-
Утилизация RAM: не более 80%.
Эти требования были установлены на основании экспертной оценки и служат ориентиром, поскольку специфические требования к системе не были предъявлены.
2. Требования к количеству неуспешных запросов
Для обеспечения надежности системы количество неуспешных запросов не должно превышать следующие показатели, в зависимости от интенсивности входящей нагрузки:
-
Тест поиска максимальной производительности (последняя ступень) — не более 0,1% от общего числа запросов.
-
Тест подтверждения максимальной производительности (в течение всего теста) — не более 0,1%.
-
Тест стабильности (в течение всего теста) — не более 0,1%.
Периоды агрегации результатов соответствуют периодам постоянной нагрузки в каждом из тестов.
3. Требования ко времени отклика и интенсивности типовых шагов бизнес-операций
Для обеспечения высокой производительности и быстрого отклика система должна удовлетворять следующим требованиям по времени отклика при выполнении типовых шагов бизнес-операций:
-
90% запросов должны обрабатываться за время не более 50 мс.
-
99% запросов должны обрабатываться за время не более 1000 мс.
-
99,9% запросов должны обрабатываться за время не более 2500 мс.
Эти требования обеспечивают предсказуемое поведение системы под нагрузкой и минимизируют вероятность задержек, критичных для бизнес-процессов.
Конфигурация стенда для Нагрузочного Тестирования (НТ)
Компонент |
Значение |
---|---|
CPU Cores |
XX |
RAM |
XXX GB |
Поиск максимальной производительности
Максимальная производительность системы определяется как нагрузка, при которой утилизация ресурсов (CPU и RAM) начинает превышать допустимые границы, указанные в разделе "Требования по утилизации ресурсов". Поиск максимальной производительности проводится через серию тестов с пошаговым увеличением нагрузки относительно базового профиля.
Шаг увеличения нагрузки:
Шаг рассчитывается по формуле:
Шаг = Значение базового профиля * 0,4 = 4.8 ≈ 5 запросов в секунду
Продолжительность каждого шага составляет 30 минут.
Результаты тестов:
Шаг |
RPS |
CPU |
RAM |
Среднее время отклика (ms) |
Минимальное время отклика (ms) |
Максимальное время отклика (ms) |
Ошибка % |
Результат |
---|---|---|---|---|---|---|---|---|
1 |
12 q/s |
31,5% |
6% |
853 |
342 |
2332 |
0,01% |
Соответствует |
2 |
17 q/s |
44,8% |
6% |
823 |
339 |
3132 |
0,00% |
Соответствует |
3 |
22 q/s |
58,6% |
6% |
851 |
353 |
2041 |
0,00% |
Соответствует |
4 |
27 q/s |
73,6% |
7% |
841 |
337 |
2652 |
0,00% |
Соответствует |
5 |
32 q/s |
88,0% |
7% |
764 |
342 |
2332 |
0,00% |
CPU превышает допустимый порог, производительность максимальна |
Графики:
Шаг 1
Шаг 2
Шаг 3
Шаг 4
Шаг 5
Вывод: Максимальная производительность системы составляет XX запросов в секунду, что превышает ожидаемую нагрузку на XX%. Система удовлетворяет требованиям производительности.
Тест на стабильность системы
Тест на стабильность проводится при нагрузке, соответствующей базовому профилю, на протяжении длительного времени (4 часа).
Результаты теста на стабильность:
RPS |
CPU |
RAM |
Среднее время отклика (ms) |
Минимальное время отклика (ms) |
Максимальное время отклика (ms) |
Ошибка % |
Результат |
---|---|---|---|---|---|---|---|
12 q/s |
33,6% |
7% |
503 |
343 |
4116 |
0,00% |
Соответствует |
Графики:
Вывод: На протяжении 4 часов тестирования стабильности системы процент отказов составил 0%, нагрузка равномерно распределена. Система удовлетворяет описанным показателям производительности.
Автор: d-element