Одним из критически важных этапов разработки веб-приложений является нагрузочное тестирование. Этот процесс необходим для выявления потенциальных узких мест в системе, а также для обеспечения того, что приложение способно выдерживать предполагаемое количество пользователей и запросов без ухудшения производительности.
Введение в нагрузочное тестирование
Нагрузочное тестирование представляет собой процесс имитации различных уровней пользовательской активности с целью оценки производительности веб-приложения. Основная задача такого тестирования — определить, насколько эффективно система справляется с возрастающим трафиком и где находятся ее пределы. В процессе нагрузочного тестирования выявляются критические точки отказа и оценивается максимальная пропускная способность приложения.
Основные методики нагрузочного тестирования
Пиковая нагрузка (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("http://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 |
Расчетное количество запросов в час на основе максимального количества запросов:
![](https://habrastorage.org/getpro/habr/upload_files/f33/789/ece/f33789ecef5ffb14ab0e1cc2598b2c34.png)
На основе 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 |
Нагрузку на объекты распределили пропорционально целевой аудитории. Запросы распределяются равномерно в течение часа:
![](https://habrastorage.org/getpro/habr/upload_files/959/531/bc7/959531bc7fa4ec5aa3bbe143d58d051f.png)
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
![График результатов теста из jMeter График результатов теста из jMeter](https://habrastorage.org/getpro/habr/upload_files/af7/874/8a9/af78748a991fd9c2c2bb13b3d948c7e6.png)
![График использования ЦПУ (Grafana) График использования ЦПУ (Grafana)](https://habrastorage.org/getpro/habr/upload_files/138/1ea/894/1381ea89410912174a83fc49134775ee.png)
Шаг 2
![График использования ЦПУ (Grafana) График использования ЦПУ (Grafana).png](https://habrastorage.org/getpro/habr/upload_files/746/a0d/aff/746a0daff05841649d23c133e6273399.png)
![График использования ОЗУ График использования ОЗУ.png](https://habrastorage.org/getpro/habr/upload_files/563/87c/4e3/56387c4e34ed41084b955f8a5337b112.png)
Шаг 3
![График результатов теста из jMeter График результатов теста из jMeter.png](https://habrastorage.org/getpro/habr/upload_files/6a7/72c/576/6a772c576cdeafbc50f956e03d71960b.png)
![График использования ЦПУ (Grafana) График использования ЦПУ (Grafana).png](https://habrastorage.org/getpro/habr/upload_files/fc1/361/565/fc13615656dbef9ec06c4a832c79f4f4.png)
![График использования ОЗУ График использования ОЗУ.jpg](https://habrastorage.org/getpro/habr/upload_files/7e4/18e/d5f/7e418ed5f83a03c1af88ff51eb6e8e71.jpeg)
Шаг 4
![График результатов теста из jMeter График результатов теста из jMeter.png](https://habrastorage.org/getpro/habr/upload_files/57d/14d/2b2/57d14d2b2f0f5c809f10fa91d1b44010.png)
![График использования ЦПУ (Grafana) График использования ЦПУ (Grafana).png](https://habrastorage.org/getpro/habr/upload_files/793/662/2d6/7936622d66af3bae07d3f78efe7a1f88.png)
Шаг 5
![График результатов теста из jMeter График результатов теста из jMeter.png](https://habrastorage.org/getpro/habr/upload_files/3de/8a9/f44/3de8a9f4457890d150a6027313067456.png)
![График использования ЦПУ (Grafana) График использования ЦПУ (Grafana).png](https://habrastorage.org/getpro/habr/upload_files/9c0/c85/7aa/9c0c857aa478cfd57599a88b9c229c7a.png)
![График использования ОЗУ График использования ОЗУ.png](https://habrastorage.org/getpro/habr/upload_files/d8e/fd6/67d/d8efd667d18ccd2123625f26b3a46060.png)
Вывод: Максимальная производительность системы составляет XX запросов в секунду, что превышает ожидаемую нагрузку на XX%. Система удовлетворяет требованиям производительности.
Тест на стабильность системы
Тест на стабильность проводится при нагрузке, соответствующей базовому профилю, на протяжении длительного времени (4 часа).
Результаты теста на стабильность:
RPS |
CPU |
RAM |
Среднее время отклика (ms) |
Минимальное время отклика (ms) |
Максимальное время отклика (ms) |
Ошибка % |
Результат |
---|---|---|---|---|---|---|---|
12 q/s |
33,6% |
7% |
503 |
343 |
4116 |
0,00% |
Соответствует |
Графики:
Вывод: На протяжении 4 часов тестирования стабильности системы процент отказов составил 0%, нагрузка равномерно распределена. Система удовлетворяет описанным показателям производительности.