В ходе тестирования некоторых продуктов компании Positive Technologies возникла необходимость проведения быстрых стресс-тестов одного веб-сервиса. Эти тесты должны были быть простыми и быстрыми в разработке, нетребовательными к аппаратным ресурсам и одновременно с этим давать значительную нагрузку однотипными HTTP-запросами, а также предоставлять статистические данные для анализа системы под нагрузкой.
Для их реализации мы исследовали и опробовали некоторое количество инструментов, среди которых были Apache JMeter и написанный нами на Python скрипт LogSniper, который выполнял реплей заранее подготовленных серверных логов с HTTP-запросами на цель.
От использования JMeter было решено отказаться из-за значительной сложности подготовки и проведения тестов, высоких требований к производительности нагрузочного стенда и довольно малых мощностей нагрузки, хотя эти недостатки и компенсировались высокой информативностью собираемой статистики. LogSniper был отклонен из-за малой мощности генерируемой нагрузки и здесь даже простота подготовки нагрузочных HTTP-пакетов не смогла перевесить. Другие известные инструменты нам по тем или иным причинам тоже не подошли.
В итоге мы остановились на инструменте Яндекс.Танк, о котором узнали, побывав на конференции YAC-2013 и пообщавшись со специалистами Яндекса. Этот инструмент полностью отвечал всем нашим требованиям к простоте подготовки теста и к генерируемой нагрузке.
Что это
Яндекс.Танк — инструмент для проведения нагрузочного тестирования, разрабатываемый в компании Яндекс и распространяемый по лицензии LGPL. В основе инструмента лежит высокопроизводительный асинхронный генератор нагрузки phantom: он был переделан из одноименного веб-сервера, который «научили» работать в режиме клиента. При помощи phantom можно генерировать десятки и сотни тысяч HTTP-запросов в секунду (http-requests per second, http-rps).
В процессе своей работы Танк сохраняет полученные результаты в обычных текстовых журналах, сгруппированных по директориям для отдельных тестов. Во время теста специальный модуль организует вывод результатов в консольный интерфейс в виде таблиц. Одновременно запускается локальный веб-сервер, позволяющий видеть те же самые результаты на информативных графиках. По окончании теста возможно автоматическое сохранение результатов на сервисе Loadosophia.org. Также имеется модуль загрузки результатов в хранилище Graphite.
Некоторые полезные ссылки:
- код проекта на GitHub;
- официальная документация по настройке и использованию инструмента;
- информация о модулях Танка в wiki разработчиков;
- презентация об истории возникновения инструмента;
- история возникновения сервиса нагрузочного тестирования в Яндексе и разработки Танка;
- Яндекс-клуб, посвященный вопросам использования инструмента.
Сегодня мы не будем подробно останавливаться на установке и настройке Танка, поскольку эту информацию легко найти в сети, а сразу перейдем к описанию своего опыта его использования.
Сравнение производительности двух аналогичных веб-сервисов
В ходе работы нам потребовалось сравнить характеристики двух веб-сервисов, работу которых можно примерно описать как «прозрачные HTTP-прокси, перенаправляющие входящие запросы на backend-приложение».
Общую схему работы можно изобразить следующим образом:
На стенде с Танком использовался генератор нагрузки phantom с включенным монитором производительности.
В качестве стенда web-proxy на схеме использовались два тестируемых веб-сервиса, с которых при помощи агента Танка снимались показатели производительности. Условно назовем их Эталонный веб-сервис и Испытуемый веб-сервис. Нам требовалось понять, соответствует ли производительность испытуемого веб-сервиса эталонному.
Для backend использовалось небольшое веб-приложение, запущенное под Nginx и возвращающее одну простую HTML-страничку.
Выявленные ограничения
Перед началом работ мы собрали информацию об ограничениях виртуальных стендов, на которых была построена вся тестовая инфраструктура.
Характеристики стенда backend-приложения:
- 8 vCPU, 4 GB, 10 Gb/s,
- веб-сервер Nginx.
Максимальная отдача сервера, которой удалось добиться, составила ~ 25 000 http-rps, но и при нагрузке выше 25k http-rps работа стенда не была нарушена.
Стенд Танка с характеристиками 16 vCPU, 8 GB, 10 Gb/s позволил реализовать нагрузку до 300 000 http-rps.
Пропускная способность виртуальной среды ESXi, определенная с помощью Iperf, составила 8 Gb/s в одну сторону, 4 Gb/s при двухсторонней нагрузке между двумя виртуальными машинами.
Метрики и критерии сравнения
Перед началом работы для дальнейшего измерения мы определили следующие метрики каждого профиля нагрузки:
- http_rps_out — значение http-rps, отправляемое с Танка на веб-приложение,
- http_rps_in — значение http-rps, принимаемое на Танке со стороны веб-приложения,
- http_request_size — размер http-запроса в байтах,
- send_requests — количество отправленных HTTP-запросов,
- bs_out — bytes per seconds, байт в секунду — параметр определяет скорость отправки данных с Танка,
- bs_in — значение bs, отправляемое с веб-приложения в сторону Танка,
- test_time — время теста в секундах,
- response_time_med — среднее время, в которое укладывается 90% всех ответов.
Зная число HTTP-запросов и их размер, получаем, что bs и http-rps связаны по формуле: bs = http_rps * http_request_size.
В данном случае мы решили выбрать следующие критерии для сравнения работы веб-сервисов под нагрузкой:
- За все время теста значение параметра «время, в которое укладывается 90% ответов» у испытуемого веб-сервиса должно быть не больше, чем у эталонного веб-сервиса.
- На отрезке возрастания нагрузки на очередные 1000 http-rps значение параметра «время, в которое укладывается 90% ответов» у испытуемого веб-сервиса должно быть не больше, чем у эталонного веб-сервиса.
- За все время теста общее количество правильно обработанных запросов у испытуемого веб-сервиса должно быть не меньше, чем у эталонного веб-сервиса.
Аналогичным образом можно определить иные критерии нагрузочных тестов для любых проектов.
Тестовые HTTP-запросы
Для одного из профилей нагрузочных тестов нам требовалось создать смешанный HTTP-трафик из GET- и POST-запросов с линейным возрастанием нагрузки до 10k http-rps в течение 10 минут.
GET /loadtest/index.php?id=1&login=user&pwd=password HTTP/1.1
X-Sniffer-Forwarded-For: yandex-tank-example-domain.ptsecurity.ru
Host: backend-example-domain.ptsecurity.ru
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
POST /loadtest/index.php HTTP/1.1
X-Sniffer-Forwarded-For: yandex-tank-example-domain.ptsecurity.ru
Host: backend-example-domain.ptsecurity.ru
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Content-Length: 32
id=1&login=user&pwd=password
POST /loadtest/index.php HTTP/1.1
X-Sniffer-Forwarded-For: yandex-tank-example-domain.ptsecurity.ru
Content-Type: multipart/form-data; boundary=validFile
Host: backend-example-domain.ptsecurity.ru
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Content-Length: 150
--validFile
Content-Disposition: form-data; name="login"; filename="validFile.txt"
Content-Type: text/plain
Valid file content
--validFile--
Чтобы упростить подготовку патрона для такого смешанного трафика, мы сделали скрипты, аналогичные perl-скриптам, предлагаемым на форуме.
Сбор данных и анализ результатов
После подготовки запросов мы просто запустили Танк стандартным образом и выполнили нагрузочный тест со смешанным трафиком для обоих тестируемых веб-сервисов.
Результаты для эталонного веб-сервиса
Информация веб-монитора Танка:
Информация консоли Танка:
Результаты для испытуемого веб-сервиса
Информация веб-монитора Танка:
Информация консоли Танка:
Даже судя по графикам, испытуемый сервис показывал результаты не хуже, чем эталонный. Проверив все три формально определенных выше критерия, мы в этом убедились.
- Испытуемый сервис удовлетворяет первому критерию, так как для 90% запросов среднее время ответов для испытуемого сервиса не превышало такой же показатель для эталонного сервиса.
- Требование второго критерия выполнялось для каждого этапа нагрузки.
- Судя по анализу статус-кодов ответов, записанных в журналы Танка, испытуемый веб-сервис принял и корректно обработал запросов больше, чем эталонный веб-сервис.
Выводы
По результатам работы с Яндекс.Танком можно с полной ответственностью заявить, что этот инструмент отлично подходит в тех случаях, когда требуется быстро провести нагрузочное тестирование веб-приложений без их сложной подготовки и при этом получить множество полезных статистических данных для анализа производительности.
Кроме того, он хорошо внедряется в имеющиеся системы автоматизации. Например, для упрощения работы со стендом Танка — управления, запуска, подготовки патронов для лент, контроля за процессом тестирования и сбором результатов — мы без особых усилий написали класс-обвязку на Python, который подключается к стенду по SSH и выполняет все перечисленные действия. Затем этот класс был встроен в нашу существующую систему авто-тестирования.
Дополнительно вы можете посмотреть, как подключить и использовать высокопроизводительную систему Graphit для анализа большого числа графиков (о ней рассказывалось в одной из презентаций на конференции YAC-2013). Ее также можно приспособить для нужд нагрузочного тестирования с использованием Яндекс.Танка.
Выражаю благодарность моему коллеге Олегу Каштанову за техническую поддержку.
Автор: Тимур Гильмуллин (блог).
Автор: ptsecurity