Что такое pacing в нагрузочном тестировании
Шаг нагрузки — pacing JMeter
1. Что такое шаг нагрузки
При планировании нагрузки важно выдержать заданную интенсивность работы теста. Это достигается за счёт того, что используется фиксированный шаг нагрузки — такой интервал времени в течение которого гарантировано выполняется один проход сценария.
Обозначим шаг нагрузки как T (минут).
Тогда за минуту работы, один виртуальный пользователь, выполнит 1/T сценариев. Интенсивность работы одного виртуального пользователя будет равна 1/T сценариев в минуту.
А если будет работать N виртуальных пользователей, то они суммарно будут выполнять N/T сценариев в минуту.
2. Калькулятор шага нагрузки
Для удобства расчёта шага нагрузки к текущему заданию сделан калькулятор шага нагрузки в виде Excel-документа:
Калькулятор шага нагрузки и подбора количества пользователей для требуемой интенсивности
Скачать калькулятор шага нагрузки (документ Microsoft Excel):
Для редактирования предназначены жёлтые ячейки документа.
3. Как задать шаг нагрузки в Apache.JMeter
описаны компоненты, которые рекомендуется использовать при выполнении задания, которые обычно используются.
В том числе компоненты Test Action и
Constant Throughput Timer, которые используются для задания фиксированного шага нагрузки в JMeter.
Если опустить другие элементы, то нужные для задания шага нагрузки блоки такие:
А если ещё более кратко, то первым действием в катушке , для которой фиксируется шаг работы задаётся Sampler с типом
Test Action:
Тут в поле Name я отразил пример длительности шага « 80 секунд «, каждый волен выбирать свою длительность. Это как пример. Указывается просто, чтобы не забыть размер шага.
Дочерним элементом добавляется timer Constant Throughput Timer:
3.1. Механизм работы связки «Test Action» и «Constant Throughput Timer»
Что происходит при таком составе компонент:
Между моментами начала шага 2.3 и 3.3 всегда будет фиксированный временной интервал. При условии, что длительность выполнения 2.3 не будет превышать размер шага нагрузки.
Контролируя расстояние на временной школе между моментами выполнения пустого Test Action мы контролируем шаг нагрузки, отделяем одну итерацию сценария от другой.
3.2. Проверка правильности выбора шага нагрузки
Для проверки нужен тестовый запуск. Запустить тест и посмотреть на длительность выполнения сценария. Если она превышает шаг, то прервать тест, выбрать новый шаг, пересчитать параметры и повторить отладку.
Чтобы убедиться, что длительность выполнения шагов сценария не превышает шаг, в качестве корневого элемента используется Transaction Controller. Один учитывающий паузы и второй, вложенный в него, считающий время без учёта таймеров.
Используя транзакции верхнего уровня и сводные отчёты:
Можно посмотреть максимальную длительность выполнения корневой транзакции. И если эта длительность превышает шаг, допустим, « 80 секунд «, то надо выбрать новый шаг и пересчитать параметры:
4. Как задаётся интенсивность в HP LoadRunner
В HP LoadRunner всё тоже самое, нужно задать фиксированный шаг нагрузки и задать количество виртуальных пользователей.
4.1. Шаг нагрузки в HP LoadRunner
Шаг нагрузки в HP LoadRunner задаётся в Runtime Settings на вкладке Pacing:
Шаг задаётся в секундах. В HP LoadRunner нам надо задать фиксированный шаг для итерации в секундах, а в Apache.JMeter задаётся фиксированная частота — величина обратная размеру шага (итераций в минуту). А смысл один и тот же.
Количество пользователей задаётся в HP LoadRunner Controller на вкладке Design, в разделе Scenario Schedule.
5. Пример расчёта шага нагрузки и визуализация
Простой пример расчёта шага нагрузки, когда сразу шаг целый, интенсивность и количество пользователей целые. Демонстрация взаимного отношения величин.
» data-medium-file=»https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=300″ data-large-file=»https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=1024″ src=»https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=1080″ alt=»Простой пример расчёта шага нагрузки, когда сразу шаг целый, интенсивность и количество пользователей целые. Демонстрация взаимного отношения величин.» srcset=»https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=1080 1080w, https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=150 150w, https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=300 300w, https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=768 768w, https://loadtestweb.files.wordpress.com/2017/08/pacing1.png?w=1024 1024w, https://loadtestweb.files.wordpress.com/2017/08/pacing1.png 1441w» sizes=»(max-width: 1080px) 100vw, 1080px» /> Простой пример расчёта шага нагрузки, когда сразу шаг целый, интенсивность и количество пользователей целые. Демонстрация взаимного отношения величин.
Допустим, по результатам анализа логов или по результатам пробного запуска тестового сценария на 100 итерациях тестирования мы выяснили, что длительность выполнения сценария укладывается в 15-20 минут.
При выборе шага нагрузки можно сделать запас. На случай, что под высокой нагрузкой длительность выполнения превысит обычную. Если речь идёт о высокой нагрузке, то шаг сценария может быть равен 2-3-м обычным длительностям, в рамках разумного.
Пусть в качестве шага нагрузки мы выбираем 30 минут.
Пусть во время нагрузочного тестирования нам необходимо получить 10 выполнения сценария в час — такова целевая интенсивность.
Тогда понадобится всего 5 пользователей, выполняющих сценарии с интенсивностью 1/30 сценария в минуту или 2 сценария в час.
Визуализация того, что такое фиксированный шаг нагрузки. И как реальная длительность выполнения сценария укладывается в этот шаг. За счёт постоянного шага появляется предсказуемость — сколько операций будет выполнено в единицу времени, за час.
Визуализация того, что такое фиксированный шаг нагрузки. И как реальная длительность выполнения сценария укладывается в этот шаг. За счёт постоянного шага появляется предсказуемость — сколько операций будет выполнено в единицу времени, за час.
Под малой нагрузкой — в начале теста сценарии будут выполнять быстро.
При высокой нагрузке, длительность выполнения сценариев будет расти и может приблизиться к шагу нагрузки.
4.1. Строевой шаг
Важно выбрать шаг нагрузки достаточно большим. Чтобы зависающие сценарии не нарушали «строевой шаг».
4.2. Смена профиля нагрузки
Для большей интенсивности нужно пропорционально увеличить количество виртуальных пользователей. Это очень удобно — увеличить нагрузку в 50 раз, увеличив количество пользователей в 50 раз.
Нагрузочное тестирование веб-проекта — без купюр
Друзья, добрый день!
Продолжаем серию публикаций «без купюр» о проектах, связанных с разработкой, часто с приставкой «веб». Поговорим сегодня о нагрузочном тестировании. Проблема в том, что часто ни клиент, ни руководитель проекта не понимают, зачем оно нужно, какие риски оно позволяет снизить, как его организовать и как, а это самое, думаю, сложное, интерпретировать его результаты с пользой для бизнеса. Наливаем кофе и поехали…
Зачем нужно нагрузочное тестирование веб-проекта?
Дело в том, что если для удержания качества в некоторых веб-проектах еще пишут автотесты, то контролем производительности на стадии разработки мало кто занимается в принципе. Увидеть веб-проект и с автотестами и с бенчмарками кода — большая редкость. Гораздо чаще и по разумным причинам при разработке придерживаются следующих эвристик, обладающих хорошим соотношением польза-стоимость:
Возьмем кеширование. При разработке часто некогда задумываться над тем, как часто кэш может перестраиваться. А зря. Если перестройка кэша, скажем, каталога товаров, занимает длительное время и кэш сбрасывается при добавлении одного товара, то от кэширования будет больше вреда, чем пользы.
Именно поэтому, кстати, не рекомендуется использовать встроенный кэш запросов MySQL, страдающий от похожей проблемы: при изменении хотя бы одной записи таблицы кэш таблицы полностью сбрасывается (представим таблицу из 100к строк и абсурдность ситуации становится очевидна).
Аналогичная ситуация с запросами к MySQL. Если запросы выполняются по индексам, то, в общем случае, запросы будут выполняться… «быстрее». Можно верить, что время выполнения таких запросов логарифмически зависит от объема данных (O(log(n))). Но на практике часто оказывается, что одни запросы влияют на другие, используя одновременно общие подсистемы БД (сортировка на диске, который начинает тормозить) и сразу предвидеть это — нельзя.
Также часто при нагрузке выявляются любопытные особенности операционной системы, в частности, переполнение диапазона исходящих клиентских портов TCP/IP, при интенсивной работе с memcached. Или apache забивается запросами на обработку картинок, т.к. при конфигурации забыли настроить их обработку кэширующим прокси-сервером nginx.
Иногда забывают установить в MySQL путь для временных таблиц на диск, отображающий данные в оперативную память («/dev/shm»), из-за чего при возрастании нагрузки сервер БД ложится от интенсивных сортировок.
Также, при добавлении в веб-проект данных, в объеме, приближенном к боевому, запросы и алгоритмы начинают агрессивно проявлять свою «О-нотацию»: если cartesian для небольшого объема данных незаметен, то при появлении боевого объема сервер БД от напряжения становится красным.
Примеров можно привести еще массу, остановимся пока на этом. Главное понять, что нагрузочное тестирование — необходимо. Потому что заранее предусмотреть все возможные варианты «торможения» веб-системы среднего размера очень дорого, очень долго и экономически нецелесообразно.
Как определить целевые показатели нагрузочного тестирования?
Тут важно понять, что на самом деле покажет и вам и клиенту уровень качества веб-системы при нагрузочном тестировании. Нет ничего лучше конкретных примеров целевых показателей нагрузочного тестирования, плохих и хороших:
Все просто! Сейчас нарисую и покажу в прекрасной среде для анализа данных: Jupyter notebook/Python.
Допустим, на веб-сайт сделали 10 хитов с таким временем в миллисекундах:
Теперь отсортируем время выполнения хитов по возрастанию:
Мы в шаге от понимания медианы, 25 и 75 перцентелей. Все просто — разделим график пополам и в середине будет «медиана» (цифра 1 на графике). Первая четверть графика будет соответствовать 25 перцентилю (цифра 2 на графике) и третья четверть будет соответствовать 75 перцентилю (цифра 3 на графике). Соответственно получаются и другие перцентили (или, как их еще называют, квантили) — 90, 95, 99 и т.п.:
А так будет выглядеть распределение (гистограмма) по времени выполнения указанных выше хитов. Как видим, все очень наглядно и просто:
А вот так можно быстро построить распределение (гистограмму) по логу запросов нагрузочного тестирования. Модифицируйте под свой формат лога:
И получится примерно такая картина:
Надеюсь теперь все стало ясно и на свои места. Если нет, спрашивайте в комментариях.
Время проведения нагрузочного тестирования
Часто спрашивают — сколько времени должно продолжаться нагрузочное тестирование веб-проекта? Тут простая эвристика — в операционной системе нередко раз в сутки выполняются запланированные задания: бэкапы, ротация логов и т.п., поэтому время проведения нагрузочного тестирования должно быть не меньше, правильно, суток. Если веб-проект на Битрикс, то в платформе также выполняется немало запланированных в расписание заданий и желательно нагружать веб-систему не меньше суток.
Планирование распределения нагрузки
Если уже есть эксплуатируемый веб-сайт, то можно, да, взять логи посещения оттуда и нагружать новую веб-систему, используя их. Но часто решают задачу нагрузки только разрабатываемой веб-системы. Для планирования распределения нагрузки часто хорошо подходит модель разделения предполагаемых цепочек посещения сайта на доли. Например:
Расчет интервалов и нагрузочных потоков несложно сделать в Excel или на листике карандашом.
Структура нагрузочной цепочки
Тут важно учесть особенности жизненного цикла пользователя веб-системы. Часто пользователи авторизуются, а потом ходят по веб-сайту. Для этого в начало нагрузочной цепочки нужно поместить действия, приводящие к авторизации:
Коню ясно, что нельзя при нагрузочном тестировании дергать только одну детальную страницу каталога, поэтому полезно считывать и ротировать их список из CSV-файла:
Между хитами, разумеется, нужно делать случайные паузы — так мы ближе приблизимся к нагрузке, создаваемой реальными пользователями. Не забываем также о сохранении и возвращении на сервер значений cookies:
Глобальные переменные нагрузочных цепочек, в том числе их число потоков, настраиваются просто. Определенные глобальные переменные можно использовать затем в разных местах нагрузочных цепочек:
Как сделать так, чтобы нагрузочное тестирование благополучно закончилось?
На практике, почти всегда, нагрузочное тестирование в первые минуты-часы обрушивает веб-систему, все начинает дымиться, затем гореть, сайт не открывается, MySQL падает в своп и не дает к себе подключиться, LA на серверах приближается к 100, разработчики начинают бегать со словами «это не должно было произойти», а сисадмины с ухмылкой обычно отвечают «справедливость в жизни есть!» и начинают пить пиво в серверной.
Но чтобы понять, почему все упало и что чинить, чтобы через сутки показать клиенту результаты «успешного» нагрузочного тестирования, необходимо предварительно включить запись основных метрик жизнедеятельности операционной системы — это легко сделать в бесплатных продуктах класса munun/cacti.
Перечислю, что происходит при коллапсе веб-системы чаще всего и как это можно исправить.
Прежде всего «забивается» запросами веб-сервер apache или php-fpm:
Чаще всего это происходит из-за коллапса MySQL — вырастает число висящих потоков запросов:
Чем это обусловлено? Часто сверху забывают забивают ограничить число apache или потоков запросов к МySQL, что вызывает выпадение приложений из оперативной памяти в медленный своп с конвульсиями:
Тут видна внезапная активность при работе со свопом, нужно разбираться, кто выпал в своп и откуда:
Однако, иногда проблема оказывается на стороне медленной дисковой подсистемы. В этом случае резко вырастает LA и процент утилизации диска приближается к 100 (правый нижний график):
Очевидно, что я вскрыл только часть самого интересного, что может начаться с веб-проектом при нагрузочном тестировании. Но ведь главное — задать верное направление и выстроить правильный процесс. Спрашивайте в комментариях, что повылазило у вас при нагрузке, постараюсь помочь.
Интерпретация результатов нагрузочного тестирования
Обычно после 5-10 перезапусков и корректировок, нагрузочное тестирование начинает свой полет и успешно завершается. В результате у вас должен быть набор примерно таких логов для дальнейшего анализа:
Имея эти артефакты, вы можете, используя простой awk-скрипт в начале поста, построить распределения (гистограммки) по этим логам и посчитать число и типы HTTP-ошибок. По сути, вы можете сформировать очень емкий и полезный для бизнеса и принятия решений отчет об успешности нагрузочного тестирования примерно такого содержания:
В течение суток сделан 1 млн. хитов. 25% хитов сделаны менее, чем за 50 мс, 50% хитов сделаны менее, чем за 0.5 сек (медиана), 75% хитов сделаны менее, чем за 1 сек, 95% хитов сделаны менее, чем за 5 сек, число ошибок HTTP — 0.01%. Тестовые данные: каталог, пользователи, новости, статьи были залиты в объеме, приближенном к ожидаемому.
Один разработчик — застрелился.
Главная — Новости — Детальная новости = 50%
Главная — Обзор каталога — Детальная каталога = 30%
Детальная каталога — Обзор каталога — Детальная каталога = 15%
Результаты поиска — Детальная каталога = 5%
Графики использования ресурсов серверов:
…
Это уже хороший и понятный отчет о нагрузочном тестировании веб-системы. Для любителей острой боли еще можно рекомендовать при нагрузочном тестировании включить ежеминутный импорт-экспорт данных на веб-сайт из систем класса SAP, 1C и т.п. и синхронные соединения по TCP/IP сокетам с внешними сервисами курсов, скажем, криптовалют 🙂
Но, скажу честно, если импорт-экспорт сделать аккуратно, по совести, то нагрузочное тестирование и при таких условиях покажет приемлемые для бизнеса цифры.
Откуда берутся ошибки при нагрузочном тестировании?
Кстати да, мы не осветили этот момент. Из банальных причин обычно всплывает отсутствие балансировки между nginx — apache — mysql воркерами. Т.е. воркеры сверху не ограничивают, в результате в apache может подняться сразу 500 воркеров (каждый иногда по 100 МБ) и на MySQL прийдут сразу 500 потоков с запросами — что вызовет всплеск HTTP 50х ошибок и возможный коллапс.
Тут рекомендуется ограничить число apache/php-fpm воркеров до числа, умещающегося в ОЗУ и, аналогично, ограничить число потоков на MySQL, для защиты от переполнения доступной оперативной памяти. Идея проста — пусть клиенты ждут перед nginx, немного может замедляясь на асинхронных и неблокирующих TCP/IP сокетах, чем «ломятся» сразу в apache/MySQL.
Из более неприятных причин тут может быть segfault PHP. В этом случае необходимо включить сбор coredump и с помощью gdb посмотреть, почему это происходит. В большинстве случаев через обновление/конфигурацию PHP проблему удается обойти.
Что осталось за кадром
Ходят упорные слухи, что современный фронтэнд для веба так активно зажил своей жизнью, что классическое нагрузочное тестирование бэкэнда, приведенное в данном посте, уже не закрывает всех возможных рисков зависания построения веб-страницы в «потрохах» Angular/React/Vue.js — поэтому не используйте тяжелый и непрозрачный, плохо тестируемый фронтэнд можно, при необходимости, адаптировать нагрузочные цепочки и к такой ситуации.
В любом случае, если результаты нагрузочного тестирования бэкэнда показали хорошие цифры, а веб-сайт продолжает тормозить в браузере, уже понятно, кого «бить по наглой рыжей морде» 🙂
Если серьезно, то в ближайших постах мы надеемся осветить и эту важную тему.
Итоги и выводы
Итого — нет ничего сложного в организации и проведении полезного для разработки и бизнеса нагрузочного тестирования веб-системы.
Для проведения нагрузочного тестирования важно привлекать не только разработчиков, но и экспертов по операционным системам и железу — опытных системных администраторов, и тогда проблемы «выпадения в своп» или «переполнения локального диапазона IP-адресов» не вызовут кровотечения из глаз и обмороков.
Удачи, друзья и задавайте вопросы в комментариях!
Что такое pacing в нагрузочном тестировании
Что пишут в блогах
2 декабря выступала в Костроме у Exactpro Systems с темой «Организация обучения джуниоров внутри команды». Уже готово видео! Ссылка на ютуб — https://youtu.be/UR9qZZ6IWBA
Привет! В блоге появляется мало новостей, потому что все переехало в telegram.
Стоимость в цвете — 2500 рублей самовывозом (доставка еще 500-600 рублей, информация по ней будет чуть позже)
Онлайн-тренинги
Что пишут в блогах (EN)
Software Testing
Разделы портала
Про инструменты
Оригинал этой статьи находится в блоге компании Veeam на хабре.
Тестирование программного обеспечения принято делить на много видов. Тут вам и функциональное тестирование, и модульное, и тестирование безопасности, и многое другое. Есть и редкие подвиды, такие как юзабилити тесты или тестирование локализации. Но определённым особняком всегда стояло загадочное для многих нагрузочное тестирование. Одна из основных причин для этого — высокие требования к уровню технических знаний инженера, который решит заняться проверкой работы продукта под нагрузкой и его способностью масштабироваться. Предлагаем вам вместе с нами глубже разобраться в вопросе в этой статье.
Нагрузочное тестирование — основы
Если усреднить сухие определения из интернета, то получается, что нагрузочное тестирование ставит своей задачей эмулировать нагрузку, создаваемую большим количеством пользователей или операций. А его цель: найти предельные значения производительности тестируемого ПО, при превышении которых его работа перестает быть стабильной.
Нет ничего сложного в том, чтобы взять, например, легковушку, посадить в нее пять человек, в багажник положить три мешка картошки, завести и поехать по прямой. Гораздо важнее понять, какое расстояние она сможет проехать с такой нагрузкой, как поведет себя на разных дорожных покрытиях, когда потребует техосмотра. И не нужны ли ей будут конструктивные изменения. Определение таких вещей значительно важнее для качества продукта, нежели просто поиск предельных значений.
Поэтому предлагаем сойтись на таком определении: нагрузочное тестирование — это определение качества работы продукта под определённой нагрузкой на заданном интервале времени.
Звучит не очень понятно, да? Давайте попробуем развернуть эту мысль: наша задача определить, насколько хорошо продукт выдерживает повышение нагрузки, как ведёт себя при длительной работе, какие узкие места обнаруживаются, и как их можно устранить. Продолжая аналогию с нашей несчастной легковушкой, получается, что наша задача — не просто нагружать её, пока машина не сможет сдвинуться с места, а, постепенно добавляя нагрузку, проверять её поведение в максимально большом количестве жизненных сценариев. Посадили пассажиров, попробовали тронуться с места. Получилось — хорошо, значит, основная функция продолжает работать штатно. А что будет, если мы так проездим целый день? Если потратим бензина на 30% больше — это допустимо или нет? А если в пять раз больше, тогда что? Как поведёт себя машина при подъёме на гору с уклоном в 12 градусов? А если дорога будет не с асфальтовым покрытием, а с грунтовым, и прошёл дождь? Вот заехали мы в гору, но как поведут себя тормоза на спуске, и какой длины будет тормозной путь? Эдак может получиться, что класть мешки с картошкой уже и смысла не будет, т.к. наша машина перестала выполнять свои функции уже на четвертом пассажире, и нагружать её больше нет смысла.
Роль нагрузочного тестирования в жизни продукта
А так ли важно и необходимо нагрузочное тестирование, как, скажем, проверка основных функций продукта? Ведь на первый взгляд это выглядит исключительно как акт доброй воли: продукт работает, нас устраивает качество его основных показателей, и всё отлично. Но вот остались у нас ещё время и ресурсы для дополнительных проверок, поэтому давайте мы ещё себе работы придумаем и проведём тесты под нагрузкой!
Здесь лучше самим себе максимально честно ответить на вопрос: “А что будет, если мы не проведём нагрузочные тесты, и конечный пользователь столкнётся с последствиями этого решения?” Особенность нагрузочного тестирования в том, что когда пользователь подходит к тем самым экстремумам, которые мы можем заранее определить, расширить или ограничить, результат стреляет так, что мало не покажется. Если наш продукт просто перестанет работать в какой-то момент (у машины заглох двигатель, или отвалились все колёса), это мы легко отделались. А если он повредит обрабатываемые данные (отвалилось только одно колесо, машина влетела в столб и водитель погиб), то что тогда? Прежде всего мы должны думать о безопасности людей и их данных. Такие вещи могут приводить к огромным репутационным и финансовым потерям, что в перспективе может привести даже к закрытию компании.
Для продуктов, ориентированных на небольшие компании или объемы данных, нагрузочное тестирование действительно может быть не так критично. Но когда компания выходит на рынок корпоративных клиентов, где нагрузки на продукт могут быть в десятки раз выше, а финансовые риски измеряться сотнями миллионов долларов, тут уже лучше бы освоить эту область знаний.
Правда, любой опытный тестировщик вам скажет (и будет абсолютно прав), что так называемый Crash Testing проводить надо в любом случае. Хотя бы для того, чтобы знать, что случается при пиковой нагрузке, и спать чуточку спокойней. Но, опять же, если, грубо говоря, это выстреливает раз в пять лет и можно пережить неприятный момент, просто заняв выжидательную позицию — это одно. Волна прошла, недовольные побурчали, ситуация стабилизировалась, и можно работать дальше. С другой стороны, вспомните себя в тот момент, когда выходит ожидаемая вами много лет онлайн-игра. Вы её купили, заранее скачали, выгнали всех из дома, чтобы никто не мешал вам целиком и полностью насладиться моментом, и вдруг видите, что вы 100500-ый в очереди на подключение к серверу, и надо грустно ждать несколько часов. Разработчики могли предсказать наплыв игроков на релизе? Конечно, могли. Они справились с такой ситуацией? И да, и нет. С одной стороны, сервера продолжают работать и выполняют свою главную функцию. С другой стороны, игроки вынуждены ждать в очереди. Которая, в свою очередь, не только не даёт серверам упасть, но и не даёт многим насладиться игрой. Это было обдуманное решение или просто так получилось? Это абсолютно точно полностью взвешенный и обдуманный ход. Момент релиза — это классический пик нагрузки. Чтобы его сгладить, необходимо докупить очень много оборудования. Но что с ним делать после того, как пик спадёт? Как компенсировать эти затраты? Вот к таким неочевидным вопросам может привести такая штука, как нагрузочные тесты.
В какой момент подключается команда нагрузочного тестирования?
Как выглядит классический жизненный цикл любого продукта: надо собрать требования, оформить их в виде ТЗ, на основе которого разработчики напишут код, а результат их деятельности проверят QA. Затем выносится вердикт об уровне качества итогового изделия. Сразу становится ясно, что под нагрузочные тесты у нас есть время только в самом конце, т.к. зачем проверять нестабильный продукт под нагрузкой, если его поведение может измениться в любой момент?
Выглядит всё очень логичным, если бы не одно важное “но”: в современном мире любое ПО — это сложная многокомпонентная система, состоящая из разных модулей, фичей и сервисов. Когда мы добавляем что-то новое в эту систему, это может так повлиять на общую архитектуру, что весь продукт перестанет работать под нагрузкой. Поэтому новые фичи надо проверять заранее и отдельно. Как только появилась более-менее стабильная версия, уже в этот момент её следует отдавать для нагрузочных тестов. Потому что если архитектурная проблема всплывёт в самом конце, на её исправление и новые проверки придётся потратить несоизмеримо больше сил и ресурсов, чем если бы её заметили на начальных этапах.
Однако системное и регрессионное тестирование перед релизом никто не отменял. Если сначала ты проверяешь каждый компонент по отдельности, то в конце обязательно надо проверить весь продукт как единое целое. Обычно это довольно сложная и кропотливая работа, так как одновременно нагрузить все компоненты — это не тоже самое, что просто включить все имеющиеся у нас тесты и снимать метрики. Конкретно в случае нашего Veeam Backup & Replication итоговые тесты идут около месяца. То есть строится отдельная лаба, в которой задействуется максимально возможное количество функций, и ведется наблюдение за её поведением. Запороть такой длительный тест — это, мягко говоря, обидно.
Пишут ли нагрузочники баги?
Итогом труда “классического” тестировщика часто становится список обнаруженных им в продукте проблем и предложенных улучшений. А что остаётся после нагрузочного тестирования, кроме красивых графиков, из которых можно делать многозначительные выводы? На самом деле это тоже баги, просто они не могут быть обнаружены другими методами тестирования и несут в себе временные и нагрузочные метрики. Например: очень долго открывается интерфейс при большом количестве объектов, резкий скачок использования CPU при каких-то условиях, утечки памяти при долгой работе и так далее.
Плюс, как мы уже говорили в начале, только после нагрузочных тестов можно заявить предельные значения, при которых работа продукта была проверена. Проверили одновременный бэкап 10,000 машин? Отлично, значит, можно смело писать это в документацию. Обработали миллион объектов инфраструктуры — ещё одна галочка. Смогли одновременно работать с тысячей серверов — пишем best practices для клиента, как повторить это у себя. Или вы думали, что последние пишутся исходя из каких-то умозрительных вещей? Нет, это всё результат тестирования с вдумчивым анализом результатов.
Автотесты vs Нагрузочные тесты
Бытует мнение, что для нагрузочного тестирования достаточно взять уже имеющиеся автотесты и просто немного допилить их напильником. Если имеем автотест, где проверяем, как работает бэкап на одной виртуалке, то в нагрузочном тесте их должна быть тысяча, и каждая должна быть размером с дом. Вот это мы создали нагрузку так нагрузку! Вот какие мы молодцы!
И такой подход имеет полное право на существование. Особенно в моменты регрессионного нагрузочного тестирования, о котором мы говорили ранее. Автотесты действительно очень важны при анализе стабильных версий продуктов. И тут же становится видно их основное отличие: задача автотестов — покрыть максимальное количество функций в максимальном количестве их вариантов, чтобы вынести вердикт о работоспособности продукта. Грубо говоря, есть у нас функция бэкапа виртуальных машин. Внутри этой функции есть громадьё вариантов настроек и их комбинаций. И чем большее количество этих комбинаций мы проверим, тем больше мы будем уверены в качестве итоговой функции. Такова задача автотестов.
С другой стороны, у нагрузочных тестов нет задачи проверить все возможные комбинации условий и настроек. Зачастую это и невозможно из-за сложности и длительности экспериментов. Поэтому приходится отбирать ключевые сценарии. Теоретически может случиться, что изменение незначительной настройки приведёт к глобальному проседанию показателей, но это уже история про поиск иголки в стоге сена.
Хоть нагрузочное тестирование и невозможно без элементов автоматизации, доля ручных действий в нём остаётся большой. Вот пример: стоит задача проверить работу продукта под определённой нагрузкой. Мы пишем скрипт, разворачивающий лабу, и скрипт, запускающий тест, а потом ждём результатов. Если всё хорошо и полученные показатели укладываются в наши требования, то все молодцы и получился хороший продукт. Но что происходит, если всё сломалось? Отрицательный результат — тоже результат, поэтому наша задача — найти, что именно сломалось, почему оно сломалось, и как это можно исправить. Просто так написать баг и отправить разработчикам нельзя. Они заберут стенд себе и неизвестно сколько будут его держать для поиска причин. Потом они сделают фикс, начнут его проверять, и всё это может затянуться на бесконечно долгий срок. Поэтому, засучив рукава, собираем логи, дампы и начинаем сами искать ошибки. Запросто может оказаться, что проблема не в продукте, а в самой лабе. Или есть какая-то бага в операционной системе. Или, к примеру, заканчивается свободная память и надо понять, сколько её требуется дополнительно или как можно снизить утилизацию имеющейся. Это всё ручная исследовательская работа, автоматизировать которую не представляется возможным. Во всяком случае, на данном этапе развития технологий.
Правда, в области веб-серверов возможностей для автоматизации нагрузочного тестирования может быть существенно больше. Благо веб-разработка уже который год в тренде, и столкнуться с чем-то действительно уникальным бывает сложно. Если даже в сети не найдётся готового теста под необходимый вам профиль нагрузки, его всегда можно допилить или собрать из имеющихся в достатке кирпичиков.
Как стать специалистом в нагрузочном тестировании
Нагрузочное тестирование — это область на стыке нескольких профессий. Тут вам и “классическое” тестирование, и системное администрирование, и автоматизация, и проектирование систем. Опыт в любой из этих сфер может помочь быстрее вникнуть и в “нагрузку”. Полезно бывает побыть пару лет сисадмином для наработки IT кругозора и технического бэкграунда. Это отличная стартовая позиция, особенно если сам ещё не понял, чем именно хочешь заниматься в IT. Но и молодой инженер, любящий технику, может прийти в отдел нагрузочного тестирования и научиться всему прямо на месте.
Как это ни странно, но в индустрии контроля качества этих самых подходов к обеспечению качества довольно много. Они могут быть настолько разными, что, проработав в одной компании и добившись там определённых высот, в другой компании этот человек работать просто не сможет из-за разности взглядов на одни и те же вещи. Поэтому в QA принцип “Проще научить молодого специалиста, чем взять готового” остаётся актуальным, как и много лет назад. Что подводит нас к другому интересному вопросу.
Философия нагрузочного тестирования
Как всем доподлинно известно, суть работы QA не в нахождении багов или попытках сломать продукт. Главная их задача — это представить, как тестируемым продуктом будут пользоваться, и проверить, что работа продукта соответствует ожиданиям пользователей. То есть это история про попытки влезть в чужую голову и умение предугадывать желания, о которых сам пользователь ещё даже не думал.
Теперь берём нагрузочные тесты. Кажется, что никакой угадайки, а лишь только сплошной прагматизм: собираем ТЗ, основываясь на запросах клиентов, накидываем немножко сверху и начинаем методично проверять необходимые метрики. Но всё ломается как только перед нами встаёт задача протестировать абсолютно новый продукт, которым ещё никто не пользовался. В этот момент задача предугадать поведение пользователей переходит из сферы чисто функциональной в сферу количественную, которая зачастую завязана на чисто технические ограничения. И перед нами встаёт задача, во-первых, понять эти ограничения, а во-вторых, найти оптимальные методы работы при заданных параметрах. При этом надо постоянно напоминать себе о том, что мы решаем техническую проблему не ради техники, а ради удобства конечного пользователя.
У этой ситуации есть плохая и хорошая стороны. Плохая заключается в том, что если мы делаем нечто новое, чего ещё никто не делал, то можем до бесконечности заниматься решением проблем, важность которых пока даже не доказана практикой. Есть, например, аналитик, который предсказывает, что это должно быть так. А рядом с ним сидит другой аналитик, который требует того же самого, но в два раза больше. А третий вообще говорит, что это никому не надо и достаточно сделать чисто номинально.
Хорошая часть заключается в том, что у нового продукта в запасе обычно есть итерации сбора фидбека и улучшения. Не угадали с парой параметров — не беда, исправим в патче или следующем релизе. Главное, чтобы на глобальном уровне продукт успешно решал поставленную задачу.
И никто не отменял субъективные метрики из области юзабилити. В какой момент тормозящий UI можно считать проблемой? Насколько ты готов мириться с задержкой реакции на клики? Что вообще такое тормозящий UI? Кто-то считает, что проблема начинается при задержке после клика в одну секунду, а кому-то и семь секунд подождать нормально, если речь про момент пиковой нагрузки.
Получается, что нагрузочное тестирование — это вершина QA эволюции?
Нет, нет и ещё раз нет. Это просто одна из ветвей на дереве возможностей. Между ними нет никакого ранжирования по степени важности из-за разности уровней сложности при вхождении или чего-то такого. Если специалист хочет работать в функциональном тестировании, он развивается в нём. Если хочет больше кода — идёт в автотесты. Хочет только код — идет в тестирование кода (да, есть и такое). Хочет мир больших чисел и дымящихся серверов — идёт в нагрузочное тестирование. И так до бесконечности. QA — это такая область, где достаточно легко найти приложение своим желаниям.
Да, нагрузочное тестирование требует большего погружения в технику и предъявляет более серьёзные требования к знаниям стороннего ПО, чем другие виды тестирования. Но это не делает его лучше или хуже других методик, где больший упор делается на функционально-аналитическую часть, например. Технологичность всего процесса — это просто особенность, которая для кого-то может стать решающим фактором при выборе направления роста.