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

в 16:00, , рубрики: Блог компании Яндекс, нагрузочное тестирование, тестирование, тестирование в яндексе, яндекс, яндекс.танк, метки: , ,

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

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

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

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

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

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

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

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

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

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

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

Если у вас 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 — это высокопроизводительный веб-сервер, который Танк использует в качестве срелялки, тоже родом из Яндекса. Рассказ о нем можно послушать тут.

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

pip install ipaddr lxml progressbar psutil mysqldb sqlalchemy

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

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

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

[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и CollectD.

Посмотреть на залитые данные можно через веб-интерфейс, который по умолчанию слушает на порту 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!

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

Ссылки

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

Автор: Direvius

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js