пятница, 30 января 2015 г.

Как не надо проводить нагрузочное тестирование

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

Прежде, чем мы начнём рассматривать ошибки, нам нужно определиться с тем что такое нагрузочное тестирование и зачем оно нужно. Я всегда задаю себе вопросы, прежде чем начать что-то проверять - а какой вид тестирования я хочу провести? Что именно я хочу проверить? Что должно быть результатом этой работы?


Ошибка первая: Непонимание цели

И вот уже на этом шаге многие, даже опытные инженеры, ошибаются, просто пропуская его и торопясь выбрать/попробовать инструмент и "нагрузить" своё приложение.

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

Совет №1:
Прежде, чем мы приступим к нагрузочному тестированию, задайте себе вопрос - какая у нас цель? Зачем мы проводим нагрузочное тестирование?
Ответы всегда разные, но так или иначе мы проводим нагрузочное тестирование чтобы понимать - будет ли приложение работать в условиях его эксплуатации: например, приложение должно обслуживать миллионы пользователей, обрабатывать огромное количество запросов в секунду для каждого интерфейса, а так же работать безотказно, в случае выхода из строя любых из компонентов нашей системы.

Ошибка вторая: Незнание требований

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

Совет №2:
Перед началом нагрузочного тестирования надо знать как можно больше - количество клиентов при постоянной нагрузке и в пиках, количество запросов в секунду при постоянной нагрузке и в пиках, приемлемое время отклика приложения, а так же очень важно знать или продумать типичные сценарии использования, ведь мы лишь эмулируем нагрузку, при реальной эксплуатации пользователи могут вести себя иначе.

Ошибка третья: Неправильная конфигурация

Я видел отчёты о нагрузочном тестировании, в котором количество ошибок превышало количество успешных операций при одновременной нагрузке в 5 пользователей.
Такие результаты должны настораживать вас сразу - хотя нет, постойте, вы вообще не должны получать такой результат!

Совет №3:
Всегда задумывайтесь - правильно ли сконфигурирована система - перед тем, как проводить нагрузочное тестирование. Проведите функциональное тестирование после установки и настройки приложения, прежде чем приступите к нагрузочным тестам и не начинайте проверять работу системы под нагрузкой, если у вас по какой-то причине не работает основной функционал.
Так же вам не стоит забывать, что для нагрузочного тестирования, вам, скорее всего, понадобится более мощное оборудование и не стандартная для тестовых сред конфигурация системы (с оптимизацией параметров). Если раньше для тестов вам хватало два процесса, обслуживающих запросы, для нагрузочного тестирования и для продакшн установки вам, возможно, потребуется запустить 200 таких процессов (это образный пример!), или, возможно, вам потребуется изменить значения по умолчанию для параметров подключения к базе данных, поставить большие значения для очереди сообщений или изменить что-то ещё, специфичное для вашего приложения - подумайте об этом до того, как отдавать результаты проведённого нагрузочного тестирования: "А правильно ли была настроена система?".

С этой распространённой ошибкой тесно связана ещё одна, не менее распространённая:

Ошибка четвёртая: Описание конфигурации

Многие инженеры забывают включать в отчёт о нагрузочном тестировании детальную (в разумных пределах ;) ) информацию о том, какое оборудование было использовано при проведении нагрузочного тестирования и как оно было настроено, какие значения параметров по умолчанию были изменены и зачем. Такие отчёты о нагрузочном тестировании не дают корректную информацию о том, как приложение будет работать на продакшн окружении, ведь конфигурация при эксплуатации может отличаться от той, на которой проводилось нагрузочное тестирование, и понять "почему оно не работает?" без дополнительного тестирования бывает нельзя.

Совет №4:
Добавляйте информацию о конфигурации оборудования и изменяемых параметрах в конфигурационных файлах ко всем отчётам о нагрузочном тестировании.

Ошибка пятая: Одно измерение

Часто можно видеть отчёты о нагрузочном тестировании, в которых демонстрируется 1-2 графика (возможно, самых показательных), на которых отображено несколько значений - моделируемая нагрузка, время отклика системы, количество ошибок и прочее (тут все индивидуально).

В чем же заключается ошибка?

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

1. Результаты для 10% нагрузки (от средней)
2. Результаты для 100% нагрузки
3. Результаты для 120% нагрузки и для 150% нагрузки

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

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

Ошибка шестая: Мониторинг

Многие начинающие (и, к сожалению, не только) инженеры, занимающиеся нагрузочным тестированием, забывают следить за системой во время нагрузочных тестов.

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

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

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

Ошибка седьмая: Разные виды тестирования

На самом деле нагрузочное (хотя в данном контексте это не совсем верное слово) тестирование должно включать в себя такие виды тестирования, как load, performance и stress тестирование - и на некоторых проектах его действительно разделяют на разные виды тестирования и каждое проводят отдельно с предоставлением отдельных отчётов, но на многих проектах ограничиваются проведением лишь одного вида тестирования из 3ех, и при этом проводят его не достаточно правильно - потому что не задают себе вопросы - А какой вид тестирования мы проводим? Какие условия должны быть соблюдены?

Если мы спросим любого человека, хоть сколько-то знакомого с тестированием, рассказать нам, чем отличаются эти виды тестирования, он сразу же нам расскажет, что:

Нагрузочное тестирование (Load Testing)
Предполагает моделирование средней ожидаемой нагрузки на приложение в течении продолжительного времени.
Условия:
1. Средняя ожидаемая нагрузка на приложение (может быть чуть выше, но о пиковых значениях мы не говорим).
2. Проведение тестирование в течении долгого времени (возможно, тратить неделю мы не можем, но за десять минут такое тестирование тоже не делается).

Тестирование производительности (Performance Testing)
Предполагает изучение динамики таких показателей, как скорость реакции системы на действие пользователя или скорость выполнения определенных операций при изменении нагрузки на приложение.
Условия:
1. Мы измеряем такие показатели, как скорость реакции приложения на действия пользователей, скорость обновления страниц, скорость выполнения функциональных операций (например, скорость конвертации файлов или скорость создания бэкапов)
2. Измерения проводятся несколько раз при различном уровне нагрузки на систему, измерения сравниваются и делается вывод о допустимой скорости выполнения операций при определенной нагрузке на приложение.

Стресс тестирование (Stress Testing)
Предполагает моделирование пиковой нагрузки на приложение, с целью изучить какую максимальную нагрузку и как долго сможет выдержать наше приложение.
Условия:
1. Пиковые (максимальные) нагрузки а приложение, моделирование резко возрастающей и резко убывающей нагрузки.
2. Проведение тестирования с целью определения нагрузки, при которой приложение перестает нормально функционировать.
3. Добавление в сценарии тестирования "разрушающих" инфраструктуру действий (возможно) - эмуляция отказа оборудования при больших нагрузках - чтобы смоделировать чрезвычайные ситуации и изучить влияние их на работоспособность приложения под нагрузкой.

Но при проведении нагрузочного тестирования люди часто так торопятся, что проводят либо только один из видов тестирования, либо (что случается чаще всего) пытаются объединить все их в одно и проверить "всё и сразу".
Конечно, результат такого тестирования выглядит сомнительно - например, мы моделируем пиковые нагрузки в течении десяти минут и стараемся определить скорость реакции системы при таких нагрузках - после чего считаем полученные цифры окончательными и берёмся рассуждать о производительности системы. Более того - мы отдаем эту информацию нашим руководителям и заказчикам, на основе чего они делают выводы о том, какую нагрузку сможет обрабатывать приложение и какова будет скорость реакции на действия пользователей (это самые "популярные" показатели для большинства приложений)

Совет №7:
Всегда задумывайтесь о том, какой вид тестирования вы проводите, а как следствие - какие показатели вы должны измерять, какую нагрузку моделировать и что должно быть результатом такого тестирования. В отчёт о тестировании включайте описание и цели проведённого тестирования.
Мы проводили тестирование в течении 10ти минут при пиковых нагрузках, выше которых приложение уже не способно обработать корректно - но это очень часто не видно из нашего тестового отчёта, особенно, людям, не знакомым с деталями и особенностями нагрузочного тестирования.

Пожалуй, это
Самый важный совет:
Информация о тестировании используется в бизнесе. Если мы предоставляем недостоверную и неправильно обработанную и структурированную информацию - проект несёт убытки, часто несоразмерные стоимости проведения качественного нагрузочного тестирования и анализа результатов.

Ошибка восьмая: Разные профили нагрузки

Когда-то я проводил нагрузочное тестирование даже не задумываясь о том, что такое профили нагрузки, какие они бывают и зачем они нужны. Однажды я открыл для себя инструмент Яндекс.Танк и после этого всё изменилось :).

При проведении нагрузочного тестирования мы можем изменять число моделируемых пользователей или число отправляемых приложению запросов в единицу времени, тем самым моделируя не идеальную, постоянную нагрузку на приложение, а более реальную - с резкими скачками (ступенчатые), "пилообразные", постепенно линейно возрастающие и убывающие.

Совет №8:
Проводите тестирование с использованием различных профилей нагрузки и их комбинаций, это позволит смоделировать различные ситуации, которые не могут быть обнаружены при постоянной нагрузке. Анализируйте получаемые графики возрастающей / убывающей нагрузки и реакцию приложения на неё.
Я встречал проекты, на которых с помощью различных профилей нагрузки удавалось обнаружить трудноуловимые баги, такие как снижение производительности при создании / остановке дополнительных нитей(тредов) для веб сервисов - при повышении нагрузки веб сервис создает новый тред, при понижении - убивает неиспользуемые треды. При пилообразной нагрузке, когда треды постоянно создаются и сразу же убиваются, мы видим явное снижение скорости обработки запросов, вплоть до отказа приложения после длительных нагрузок с таким профилем.

Для вашего приложения может быть актуальны другие профили нагрузки - постепенно возрастающая и доходящая до пика, после чего - постепенно убывающая. Для многих проектов интересные результаты получаются при моделировании "ступенчатой" нагрузки, когда количество пользователей или запросов возрастает или убывает каждые N секунд на M, например, каждые 10 секунд в систему логинится 50 новых пользователей. При таких скачках система может ненадолго "подтормаживать", и здесь могут скрываться новые дефекты, которые нельзя будет обнаружить другими способами - но они потом обязательно появятся на продакшн окружениях!

Ошибка девятая: Агрессивное тестирование

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

Если в ваших тестовых отчётах мелькают графики количества сообщений об ошибках и их число не равно нулю - вам пора остановиться.

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

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

Совет №9:
При проведении нагрузочного тестирования система должна функционировать нормально, все запросы к системе должны быть обработаны успешно. При обнаружении ошибок в функционировании системы необходимо скорректировать конфигурацию системы и нагрузку, моделируемую нашими тестами.
Большинство веб сервисов с трудом справляются с нагрузкой в несколько десятков тысяч запросов в секунду, а при миллионе запросов в секунду может работать только специально подготовленное окружение - почти любое приложение можно нагрузить так, что он либо совсем перестанет отвечать на запросы, либо не сможет корректно обработать часть из них. Нам нужно помнить, что ценность нагрузочное тестирование приносит тогда, когда мы с уверенностью можем сказать сколько пользователей или запросов в секунду сможет обработать наша система без единой ошибки - эти данные позволяют правильно планировать ресурсы и организовывать поддержку приложения во время его эксплуатации.

Ошибка десятая: Анализ

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

Часто бывает интересно посмотреть на результаты нагрузочного тестирования при линейном увеличении подаваемой нагрузки и аппаратных ресурсов. Сравнение таких измерений даёт возможность оценки масштабируемости нашей системы и, например, планирования увеличения числа серверов при постоянном появлении новых пользователей. Если же мы проводим тестовые испытания лишь на одной конфигурации против только одного тестового окружения, может оказаться так, что все результаты нагрузочного тестирования, проведённого нами, неверны, потому что наше тестовое окружение имеет какие-нибудь особенности (старые жесткие диски, непропатченное ядро или что-нибудь ещё - причин может быть много).

Совет №10:
Проводите несколько тестовых испытаний и производите анализ получаемых во время нагрузочного тестирования результатов.
К анализу результатов нагрузочного тестирования так же добавим статистический анализ получаемых данных (если мы учли все советы и уверены в полученных результатах). Для  полученных данных можно, например, рассчитывать средние значения и дисперсию времени отклика приложения при различных нагрузках, а так же применить статистические критерии для оценки полученных значений - являются ли имеющиеся данные достаточными для того, чтобы судить по ним о производительности системы? - точный ответ на этот вопрос может дать только анализ проводимого тестирования и статистическая проверка полученных результатов. Но это уже следующая ступень проведения нагрузочного тестирования, перед переходом на которую необходимо устранить все описанные ошибки.

Ошибка одиннадцатая: Результаты

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

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

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

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

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


Ошибка двенадцатая: Тестирование - это процесс

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

Совет №12:
Нагрузочное тестирование не должно проводиться один раз за релиз или за весь жизненный цикл программного продукта. Это процесс, требующий проведения множества тестовых испытаний и анализа получаемой информации.
Я знаю что на некоторых проектах организовывается отдельный процесс непрерывной разработки (CI), в котором есть нагрузочные тесты - результаты этих тестов сохраняются и мы можем легко накладывать результаты проведения одних и тех же тестов для различных версий системы и сравнивать производительность - на проектах, где производительность критична, новые изменения могут быть отклонены и отправлены на доработку из за того, что производительность системы снизилась.

Ошибка тринадцатая: Знай свой инструмент

Часто нагрузочное тестирование начинается с выбора инструмента - и здесь кроется коварная ошибка. Лучше попробуйте несколько инструментов "в деле" до того, как начнёте нагрузочное тестирование, чтобы познакомиться с инструментом, понять, на что он способен и на что он не способен, какие у него есть параметры и на что они влияют. Незнание каких-то особенностей инструмента может привести к получению неверных результатов и вы даже можете никогда не узнать об этом, если не попробуете другие инструменты и не разберётесь до конца как работает ваш фреймворк для нагрузочного тестирования.

Совет №13:
Изучите и попробуйте несколько инструментов для проведения нагрузочного тестирования перед тем, как приступать в проведению нагрузочного тестирования. Используйте только те инструменты, в которых вы уверены, и представляете, как он работает и какие параметры вы можете контролировать, а какие - нет.
Часто можно видеть отчёты о нагрузочном тестировании, из которых видно, что из за незнания инструмента тестирования и его особенностей тестировалось не само приложение, а фреймворк для нагрузочного тестирования, который был использован. Яркий пример такой ситуации я как-то описывал в этом блоге. Не наступайте на эти грабли, всегда используйте проверенные инструменты и анализируйте получаемые результаты - и даже в случае, если вы ошиблись, вы сможете заметить свою ошибку и исправиться.

Ошибка четырнадцатая: Хватит ошибок или "пора учиться"

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

Совет №14:
Учитесь, стремитесь знать обо всём новом в нагрузочном тестировании, читайте истории проведения нагрузочного тестирования и сами делитесь своим опытом. Это позволит вам не останавливаться на достигнутом и всегда будет заставлять задумываться - а правильно ли я провожу нагрузочное тестирование? Стоит ли добавить новые советы в этот список?
Если вам захочется поделиться своим опытом или расширить список этих советов - пишите мне лично на почту, в скайп, подходите обсудить это, если мы с вами встретимся, пишите статьи в свой блог или сделайте доклад на конференции - и я узнаю о вашем опыте и с удовольствием научусь на ваших ошибках и буду применять ваши полезные советы ;)

В заключение хочу сказать Спасибо моим коллегам, вместе с которыми мы совершали все описанные ошибки не один раз, прежде чем я смог их сформулировать в этот список, изучая различные методики нагрузочного тестирования и инструменты для нагрузочного тестирования, а так же тем, кто уговаривал меня прочитать этот tech talk и помогал в подготовке материалов:

Максим Усиченко, Сергей Мурашов и Михаил Черник,
Спасибо вам!