- PVSM.RU - https://www.pvsm.ru -

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite [1]

Иной раз и секундного взгляда на график времен отклика хватает, чтобы сказать: сервис не полетит. Еще пара секунд — и причина найдена: ядра процессора загружены неравномерно, слишком мало потоков запущено на сервере. Как создать удобную систему сбора и хранения результатов нагрузочных тестов? Об этом сегодня мой рассказ.

Кстати, я буду рассказывать о Яндекс.Танке и Graphite на Тестовой Среде [2], регистрация на которую будет открыта ещё до 18:00 18 ноября [3]. Там можно будет задать свои вопросы вживую.

Если вы читали статью [4] doctornkz [5] о том, как организовано нагрузочное тестирование в Яндексе, то знаете, что результаты стрельб у нас лежат в хранилище, которое умеет их показывать через веб-интерфейс. Называется оно Лунапарк. Это очень удобно — провести тест и отправить ссылку на него всем заинтересованным людям (да и самому увидеть все на одной страничке). Сервис представляет собой веб-приложение, которое заточено на внутренние процессы (там и геймификация, и провязка с другими внутренними ресурсами), выкладывать которое в открытый доступ мы не планируем. Поэтому я решил рассказать, как построить подобную систему, используя только open-source продукты.

Архитектура системы

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

Система автоматизации — это модуль, который управляет запуском тестов, позволяет их параметризовывать, выполнять дополнительные действия (скачать лог продакшн-сервера или поднять тестовую среду). Все это можно осуществить с помощью таких инструментов, как Jenkins, Maven, Rake. Об этом сегодня рассказывать не буду, это тема для отдельного большого поста.

Генератор нагрузки — это рабочая лошадка, модуль, который создает нагрузку на мишень (тестовый стенд). Рассказ будет о Яндекс.Танке [6] — это модульная и расширяемая стрелялка, позволяющая использовать внутри разные генераторы, в частности, знакомый многим JMeter. Отмечу, что Танк — это open-source проект, опубликованный Яндексом в 2012 году. Он не для новичков, нужно быть на «привет, как дела?» с линуксом, а еще лучше уметь писать простые скрипты.

И наконец, хранилище результатов. Танк стреляет в сервис и замеряет времена отклика и другие параметры. Получаются временные ряды [7], которые необходимо где-то хранить, а потом отображать и анализировать. Мы будем использовать для этого Graphite [8].

Graphite — это высокопроизводительное и масштабируемое хранилище временных рядов, написанное на Python. Open-source. В него очень просто загружать данные (а еще для этого существует много разных способов на любой вкус) и потом их удобно крутить через Web-API (и для этого тоже есть куча фронтэндов). Подробно о том, как Graphite используется в Яндексе, о его архитектуре и производительности можно послушать тут [9].

Установка Яндекс.Танка

Если у вас Ubuntu — вы везунчик. Потому что вам всего-то нужно подключить репозиторий Танка и установить его также, как все другие пакеты — зависимости вытянутся сами (здесь и далее могут потребоваться права root — обеспечьте их):

# эти строки нужно добавить в sources.list:
deb http://ppa.launchpad.net/yandex-load/main/ubuntu precise main
deb-src http://ppa.launchpad.net/yandex-load/main/ubuntu precise main
apt-get update && sudo apt-get install yandex-load-tank-base

Если у вас не Ubuntu (я вот, например, хочу на MacOS попробовать), можете попробовать скачать .deb и сделать из него .rpm, но самый универсальный способ — это скачать исходники с github.

git clone https://github.com/yandex-load/yandex-tank.git

Собирать сам Танк не нужно — он на Python, однако нужно будет скачать и установить зависимости. Среди них есть Phantom — это высокопроизводительный веб-сервер, который Танк использует в качестве срелялки, тоже родом из Яндекса. Рассказ о нем можно послушать тут [10].

Необходимые python-библиотеки устанавливаются так:

pip install ipaddr lxml progressbar psutil mysqldb sqlalchemy

Кроме этого вам придется собрать из исходников Phantom. Не буду тут объяснять, как это сделать, кому нужно — пишите, расскажу.

Пришло время пострелять

Чтобы пострелять танком, нужно написать для него конфигурационный файл (я сегодня немного КО). Я не буду вдаваться в тонкости, которых много [11], приведу простейший пример:

[phantom]
address=example.org
rps_schedule=line(1, 100, 10m)
headers = [Host: example.org] [Connection: close] [Bloody: yes]
uris=/
  /list
  /img

После создания файла — просто запускаем танк командой yandex-tank. По умолчанию он ищет конфиг с именем load.ini в текущей директории. Оно пошуршит-пошуршит, постреляет, на выходе будет текстовый файл phout*.log с данными, который обычно советуют запихнуть в gnuplot. Но мы ведь не такие, правда?

Ставим Graphite

К сожалению, официального deb-пакета для Graphite на данный момент нет, поэтому ставить будем из репозитория Python (pypi):

apt-get install python python-dev python-cairo
pip install whisper carbon graphite-web django==1.5.1 Twisted==11.1.0 django-tagging

После установки копируем дефолтную конфигурацию (*.conf.example -> *.conf), например, так:

for file in /opt/graphite/conf/*.example; 
do cp $file ${file%.*}; done

По умолчанию Graphite хранит данные с разрешением в 1 минуту. Нам этого, конечно, мало, в нагрузочных тестах важна каждая секунда. Настраиваем политики хранения данных:

[load]
pattern = ^one_sec.yandex_tank.
retentions = 1s:7d,5s:1y

Что за древние письмена? Я попросил Graphite, чтобы все метрики, подпадающие под regexp, указанный в параметре pattern, он хранил в соответствии с политикой, указанной в параметре retentions:

1s:7d, 5s:1y

Тут все просто: секундная точность — семь дней, потом пятисекундная — в течение года.

And one more thing. Нужно обязательно настроить временную зону на вашу локальную, иначе, указав локальное время, графиков вы не увидете — попросту промахнетесь мимо ваших данных. Временная зона указывается в файле local_settings.py, например, так (по умолчанию файла нет):

echo TIME_ZONE = "Europe/Moscow" 
> /opt/graphite/webapp/graphite/local_settings.py

Теперь создадим таблички в django:

cd /opt/graphite/webapp/graphite
python manage.py syncdb

Чтобы запустить Graphite, нужно стартовать хранилище carbon и веб-фронтенд:

/opt/graphite/bin/carbon-cache.py start
/opt/graphite/bin/run-graphite-devel-server.py /opt/graphite/

Carbon по умолчанию ждет данных на 2003-м порту. Попробуем записать что-то в Graphite. Это очень просто, например:

echo my.favourite.metric 1 $(date +%s) | nc -q0 localhost 2003

Тут мы просто отправляем значение 1 с текущим таймстемпом в метрику «my.favourite.metric». А теперь зальем в Graphite содержимое /proc/vmstat (это уже юзабельно):

while read -r metric; 
do echo one_sec.vmstat.$metric $(date +%s); 
done < /proc/vmstat 
| nc -q0 localhost 2003

И конечно же, для заливки данных о системных ресурсах уже придумали много инструментов. Взгляните, например, на проекты Diamond [12]и CollectD [13].

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

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

Подключаем Танк к Графиту

Ну что же! Пришло время подружить наших новых знакомых. Это тоже просто. Добавляем к конфигурационному файлу Танка вот такую секцию:

[graphite]
address=localhost

Все, теперь снова можно стрелять и видеть наши результаты уже в Graphite. Кроме того, в папке с результатами теперь можно найти HTML-ку, которую Танк для нас заботливо сгенерил. В ней уже собраны графики и проставлены временные интервалы. Вот какие графики мы там видим:

Квантили и среднее время ответа

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

По графику квантилей можно видеть распределение времен ответа каждую секунду.

Число запросов в секунду с разбивкой по маркерам

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

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

Средние времена с разбивкой по маркерам

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

Как сервер реагирует на разные типы запросов — ответ тут.

Коды ответов

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

Если возникнут ошибки — вы увидите их на этом графике.

Кумулятивные квантили

Хранение результатов нагрузочных тестов Яндекс.Танка в Graphite

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

Шаблон отчета

Все помнят, что в предыдущей секции мы обсуждали, как залить в Graphite данные о системных ресурсах? Как же увидеть и эти метрики тоже? Для генерации HTML-ки с картинками, Танк использует шаблон, который можно указать в опциях:

[graphite]
template = ./my.tpl

Шаблон — это просто HTML-ка с переменными, которые Танк подменяет. Например:

<h2>RPS by marker</h2>
<img src="" />

<h2>Average response time by marker</h2>
<img src="" />

<h2>HTTP codes</h2>
<img src="" />

Одна ссылка на график в Graphite выглядит так:

http://{host}:{web_port}/render/?
width={width}&
height={height}&
from={start_time}&
until={end_time}&
target=aliasByMetric({prefix}.overall.quantiles.25_0)&
target=aliasByMetric({prefix}.overall.quantiles.50_0)&
target=aliasByMetric({prefix}.overall.quantiles.75_0)&
target=aliasByMetric({prefix}.overall.quantiles.90_0)&
target=aliasByMetric({prefix}.overall.quantiles.95_0)&
target=aliasByMetric({prefix}.overall.quantiles.99_0)&
target=aliasByMetric({prefix}.overall.quantiles.100_0)&
target=aliasByMetric({prefix}.overall.avg_response_time)&
areaMode=all

В фигурных скобках мы видим подменяемые поля, название которых говорит само за себя. Вместо {host} будет хост, указанный в настройках, вместо {start_time} и {end_time} — времена начала и конца стрельбы. Ну, вы поняли.

Что в итоге?

Итак, мы получили стрелялку, которая заливает данные в Graphite и генерит HTML-ку со ссылками на эти данные. Как теперь запускать стрельбы автоматически? По cron? Можно и так. Но удобнее использовать Jenkins. Об этом как-нибудь в следующий раз. Stay tuned!

Кстати, если вы дочитали этот текст до конца, значит, тема вам интересна. Приходите обсудить её на Тестовую среду [3]. На ней мои коллеги ко всему прочему расскажут про геймификацию и автоматизацию в нагрузочном тестировании. Приходите послушать и пообщаться!

Ссылки

tech.yandex.ru/events/yac/2013/talks/1122/ [9] — dkulikovsky@ о Graphite
github.com/graphite-project/graphite-web [14] — Graphite на github
github.com/yandex-load/yandex-tank [6] — Yandex Tank на github
github.com/BrightcoveOS/Diamond [12] — Diamond
collectd.org/ [13] — CollectD
twitter.com/direvius [15] — Follow me on Twitter

Автор: Direvius

Источник [16]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/testirovanie/48530

Ссылки в тексте:

[1] Image: http://habrahabr.ru/company/yandex/blog/202446/

[2] Тестовой Среде: http://tech.yandex.ru/events/meetings/testing-environment/?from=habr_testenv

[3] до 18:00 18 ноября: http://tech.yandex.ru/events/meetings/testing-environment/register/?from=habr_testenv

[4] статью: http://habrahabr.ru/company/yandex/blog/202020/

[5] doctornkz: http://habrahabr.ru/users/doctornkz/

[6] Яндекс.Танке: https://github.com/yandex-load/yandex-tank

[7] временные ряды: http://ru.wikipedia.org/wiki/%D0%92%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D1%80%D1%8F%D0%B4

[8] Graphite: http://graphite.readthedocs.org/en/0.9.12/overview.html

[9] тут: http://tech.yandex.ru/events/yac/2013/talks/1122/

[10] тут: http://tech.yandex.ru/events/yac/2010/talks/56/

[11] много: http://yandextank.readthedocs.org/en/latest/

[12] Diamond: https://github.com/BrightcoveOS/Diamond

[13] CollectD: http://collectd.org/

[14] github.com/graphite-project/graphite-web: https://github.com/graphite-project/graphite-web

[15] twitter.com/direvius: http://twitter.com/direvius

[16] Источник: http://habrahabr.ru/post/202446/