вторник, 18 февраля 2014 г.

Yandex Tank для нагрузочного тестирования API интерфейсов

"Каждую печеньку заворачивай в отдельные скобки"
Из разговоров QA команды во время
написания нагрузочных сценариев

  Я занимаюсь нагрузочным тестированием не каждый день, но когда я делаю это, я использую Яндекс Танк.
  Существует множество других инструментов для нагрузочного тестирования (давайте сразу определим область, для которой я это использую - это нагрузочное тестирование API интерфейсов). Например, есть ещё всем известный JMeter, при упоминании которого у многих лицо непроизвольно становится грустным (писать на нём тестовые сценарии и отлаживать их "ещё то удовольствие") или например FunkLoad (для любителей писать тесты на Python). Есть очень много других, но я выбрал ярких представителей своих "классов" инструментов для нагрузочного тестирования.
  Что же не так и почему не JMeter? Мне вот совсем не удобно писать на нём тесты. Если мне необходимо смоделировать небольшую нагрузку (до 500 пользователей), то я лучше воспользуюсь FunkLoad и напишу тесты на Python быстро и легко, особенно, если у тестируемого приложения уже есть готовый Python-client, что не редкость.
  Но и JMeter и FunkLoad имеют один существенный недостаток, который так сразу и не замечаешь, особенно, если тестировать производительность приходится нечасто или впервые, а глубокого анализа результатов никто и не требует.
  А вот когда моделируешь серьезные нагрузки в десятки и сотни тысяч запросов в секунду, сразу понимаешь всё. Казалось бы - запустил тот же тест, просто указал другое число параллельно работающих пользователей. В результате видишь что-то странное - график скачет, дисперсия вне всякого сомнения на столько большая, что достоверность результатов под вопросом. И начинаешь сомневаться.

  Все сомнения ещё только впереди - ведь когда понимаешь, что это происходит из за синхронного выполнения запросов написанных тобой тестов, то сразу и не видишь выхода. Допустим, у нас есть тестовый сценарий в нагрузочных тестах: создать элемент, задать ему некоторый атрибут, запросить этот атрибут и убедиться что он правильный и удалить этот элемент. Запускаем параллельно - получается отличная нагрузка - ведь параллельно гоняется один из самых частых сценариев использования.
  Но подождите, что это? Почему при определённом числе запросов в секунду график вдруг пополз вниз? А потом снова стремительно вверх?
  На самом деле тесты просто дожидались ответа от сервера, а сервер под нагрузкой стал отдавать результаты медленнее, что ожидаемо.
  В этот самый момент наш инструмент для нагрузочного тестирования просто ждёт ответа от сервера и ничего не делает. Дождавшись ответа, мы снова начинаем посылать запросы и снова ждём ответа. Поэтому - и это очень важно понять для всех, кто занимается нагрузочным тестированием - в таком случае подаваемая на сервер нагрузка зависит от приложения, которое мы тестируем. А это значит, что мы не контролируем тест, и значит получаемый результат может сообщить нам только о том, что мы неправильно проводим нагрузочное тестирование.

  Так мы пришли к Яндекс Танку. Ребята из Яндекса выложили этот инструмент в открытый доступ, за что им спасибо, не пришлось писать самим )
  Этот инструмент поддерживает три основных способа моделирования нагрузки:
  1) С помощью уже имеющихся JMeter сценариев (здесь мы, к сожалению, не избавимся от проблем с обратной связью и потерей контроля над тестом)
  2) С помощью самостоятельно написанной "пушки" на Python
  3) С помощью Phantom сценариев.
  Хотите сохранить своё время - сразу рассматривайте третий вариант. Phantom позволяет отправлять миллионы запросов в секунду, используя асинхронный движок, т.е. мы больше не зависим от тестируемого приложения и можем подавать именно ту нагрузку, которую хотим.
  В этом отношении Яндекс Танк замечателен так же и тем, что этот инструмент способен изменить взгляд на подход к тестированию, изменить отношение к получаемому результату, иначе взглянуть на проводимое тестирование.


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

  Конечно, у асинхронного движка для запросов есть свои особенности и недостатки. Можно сразу забыть о сценарном выполнении тестовых наборов. Вы не сможете узнать ID созданных элементов в процессе теста, вы их должны знать до запуска теста. А это означает, что привычные нам сценарии использования придётся разбивать на отдельные действия и заранее подготавливать базу данных к тестированию.
  Например, мы хотим тестировать сценарий, в котором будут создаваться пользователи, удаляться пользователи и запрашиваться список пользователей. Если мы используем JMeter, вполне нормальным было бы создать сценарии, в которых мы сначала создаём пользователя, потом запрашиваем список пользователей и потом удаляем этого же, только что созданного пользователя.
  С Phantom это не подойдёт, и нам надо изменить сценарий - создавать заранее множество пользователей, которых потом будем удалять и запускать параллельно асинхронно три типа запросов - добавление пользователя, удаление пользователя (из списка пользователей, которые будут созданы до запуска нагрузочных тестов) и получение списка всех пользователей. Согласен, назвать это удобным сложно, но привыкаешь быстро и просто иначе планируешь сценарии для нагрузочных тестов.

https://launchpadlibrarian.net/163832387/performance_bug.PNG

  И сразу начинаешь получать интересные графики, которые позволяют по-другому взглянуть на анализ результатов нагрузочного тестирования.

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

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

  Для любителей визуализаций и презентаций есть так же маленькая презентация ;)