Сбор и визуализация метрик приложения в Graphite и Graph-Explorer

от автора

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

Данная статья является руководством по настройке системы сбора и анализа метрик приложения на базе Graphite и vimeo/graph-explorer.

Мотивация

Система сбора метрик не является монолитом. При ее развертывании приходится иметь дело со значительным числом компонентов, каждый из которых каким-то образом взаимодействует с остальными, имеет свой конфигурационный файл и неповторимый способ запуска. Даже Graphite, сам по себе, состоит минимум из трех подсисем — демон сбора метрик (carbon), БД с метриками (whisper и др.) и веб-приложение для визуализации. Когда же необходимо добавить поддержку graph-explorer, все становится еще интереснее. Каждая из подсистем имеет свою обособленную документацию, но нигде нет документа, описывающего картину вцелом.

Метрики

Метрика — это последовательность (числовых) значений во времени. Очень простая вещь по сути. Фактически есть некоторый строковый ключ и соответствующий ему ряд (sample1, time1), (sample2, time2),… Типичным для Graphite способом именования метрик является разделение строковых ключей на части при помощи символа ".", например, stats.web.request.GET.time. Graphite позволяет группировать метрики с общим префиксом, используя символ "*" при построении графиков. Очевидно, что это далеко не самый гибкий способ работы с ключами. Если понадобится добавить еще какой-либо компонент к ключу, это может поломать построение графиков. Например, приведение ключа из примера выше к виду stats.web.server1.request.GET.time нарушит общий префикс для исторических данных. Вторым существенным недостатком такого именования метрик является потенциальная неоднозначность их трактования. Куда более самодостаточными были бы метрики, обладающие ключами вида service=web server=server1 what=request_time unit=ms с дальнейшей возможностью построения комбинированных графиков по общим тегам, а не только общим префиксам. К счастью, ребята из vimeo придумали metrics 2.0 и запили свой graph-explorer, работающий поверх graphite. Основная идея — это логическое представление метрик, как сущностей с набором пар тег-значение. Каждая метрика в формате 2.0 все равно в конечном итоге преобразуется в обычный строковый ключ, разделенный точками и попадает в carbon, но предварительно в отдельном хранилище создается «индекс», хранящий информацию о соответствии этих ключей и пар тег-значение. Таким образом, пользуясь информацией из индексов, graph-explorer и реализует комбинирование различных метрик на одном графике.

Общий взгляд

В общем виде система сбора метрик может быть представлена следующий диаграммой:

Таким образом, приложение (веб-сервис, демон, etc.), написанное не любом языке, через некоторый интерфейс (прослойку) отправляет метрики в коллектор, коллектор их частично агрегирует, вычисляет частоту обновления (опционально) и раз в некоторый промежуток времени отправляет их в carbon, который постепенно складывает их в хранилище. Веб-приложение тянет данные из хранилища (и частично из самого carbon) и строит для нас графики. Демон carbon на самом деле — это целых 3 демона: carbon-cache, carbon-relay и carbon-aggregator. В простейшем случае можно использовать carbon-cache. Реализацию carbon-relay можно использовать с целью шардирования (распределение нагрузки между несколькими carbon-cache) или реплицирования (отправка одних и тех же метрик на несолько carbon-cache). Демон carbon-aggregator умеет выполнять промежуточную обработку метрик перед отправкой их в хранилище. Данные метрик в carbon могут быть переданы по одному из двух форматов: в plain text (т.н. line protocol) на порт 2003 и сериализованные в pickle на порт 2004. При этом carbon-relay на выход отдает данные только в pickle (важно!).

Надстройка graph-explorer добавляет еще одно хранилище для т.н. индексов метрик. В качестве такого хранилища используется elastic search. Очевидно, что в каком-то месте представленной на диаграмме системы необходимо добавить звено, которое будет осуществлять «индексацию» метрик. Таким звеном является carbon-tagger. В итоге, система принимает следующий вид:

Стек технологий

Далее идет уже конкретика, в вашем случае возможно какой-то из компонентов будет заменен на другое решение.

Система предназначена для сбора именно метрик 2.0 с последующим их использованием в graph-explorer.

Установка

Установка будет происходить в директорию /opt/graphite, являющуюся директорией по умолчанию. Часть компонентов написана на Go, так что его также придется предварительно установить и прописать соответствующие переменные окружения. Установка подразумевает, что Go в системе один. Если у вас установлено несколько версий Go, то этот шаг можете пропустить и настроить нужную версию по своему усмотрению.

cd /opt wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz tar -C /usr/local -xzf go1.4.2.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile echo 'export GOPATH=/opt/go' >> /etc/profile echo 'export GOBIN="$GOPATH/bin"' >> /etc/profile echo 'export PATH=$PATH:$GOBIN' >> /etc/profile source /etc/profile  go env  # Вывод должен содержать следующие строчки #GOBIN="/opt/go/bin" #GOPATH="/opt/go" #GOROOT="/usr/local/go" 

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

statsd python клиент

В качестве клиента, занимающегося отправкой метрик из приложения, выбран наиболее популярный statsd. Его реализация бесконечно проста. Фактически, это отправка текстовых данных на указанный UDP/TCP-порт с добавлением минимальных протокольных служебных данных.

# внутри виртуального окружения приложения pip install statsd 

Пример использования в коде приложения:

import statsd  client = statsd.StatsClient(host='statsdaemon.local', port=8125) # отправка метрики в metrics 2.0 формате tag_is_value client.gauge('service_is_myapp.server_is_web1.what_is_http_request.unit_is_ms', <execution_time>) 

statsd

В «классической» схеме установки graphite зачастую в качестве промежуточного коллектора используется statsd. В нашем случае использован statsdaemon, так как он из коробки умеет работать с метриками 2.0, при этом сохраняя обратную совместимость с протоколом statsd. Он написан на Go и его установка чрезвычайно проста (осторожно, сейчас в README.md досадная ошибка в команде установки):

go get github.com/Vimeo/statsdaemon/statsdaemon 

После этого в директории /opt/go/bin должен появиться исполняемый файл statsdaemon. Настройки этого демона достаточно просты:

statsdaemon.ini

# --- /etc/statsdaemon.ini --- listen_addr = ":8125"  # сюда будет слать метрики statsd-клиент (приложение) admin_addr = ":8126" graphite_addr = "carbon.local:2013" # адрес carbon для агрегированных метрик, раз в flush_interval сек flush_interval = 30      prefix_rates = "stats." prefix_timers = "stats.timers." prefix_gauges = "stats.gauges."      percentile_thresholds = "90,75" max_timers_per_s = 1000 

Запуск statsdaemon:

statsdaemon -config_file="/etc/statsdaemon.ini" -debug=true 

На этом этапе уже можно запустить statsdaemon и послать в него несколько пакетов из приложения с помощью statsd-клиент. Вывод в консоль будет говорить сам за себя.

Graphite

Актуальное руководство по установке находится здесь. Установку лучше проводить внутри virtual environment, располагающегося в /opt/graphite.

sudo apt-get install python-pip python-dev pip install pip --upgrade pip install virtualenv  mkdir /opt/graphite virtualenv /opt/graphite cd /opt/graphite source bin/activate  sudo apt-get install libcairo2 python-cairo libffi-dev # установка нужных для graphite пакетов  pip install https://github.com/graphite-project/ceres/tarball/master pip install whisper pip install carbon # pip install carbon --install-option="--prefix=/opt/graphite" --install-option="--install-lib=/opt/graphite/lib" pip install graphite-web # pip install graphite-web --install-option="--prefix=/opt/graphite" --install-option="--install-lib=/opt/graphite/webapp"  # нужно для Graphite WebApp pip install uwsgi  pip install django pip install cairocffi pip install django-tagging  # инициализация webapp (cd /opt/graphite/webapp/graphite; python manage.py syncdb) 

После установки, graphite будет располагаться в /opt/graphite. Далее необходимо выполнить его конфигурацию. Пример файлов с настройками находятся в /opt/graphite/conf. Минимум, что необходимо сделать, это создать файл настроек carbon и whisper.

cp /opt/graphite/conf/carbon.conf.example /opt/graphite/conf/carbon.conf # carbon.conf содержит настройки для carbon-cache, carbon-relay и carbon-aggregator. # Необходимо настроить как минимум следующие значения в секции carbon-cache: # LINE_RECEIVER_INTERFACE = 127.0.0.1 # LINE_RECEIVER_PORT = 2003  cp /opt/graphite/conf/storage-schemas.conf.example /opt/graphite/storage-schemas.conf # storage-schemas.conf содержит настройки whisper, который по сути - fixed-size db. # Аллокация места под метрики происходит 1 раз, поэтому нужно явно задать (по # ключу метрики), с какой частотой дескритизации и за какой период хранить данные. ... 

Далее необходимо запустить carbon-cache:

carbon-cache.py --conf=conf/carbon.conf start # --debug tail -f /opt/graphite/storage/log/carbon-cache/carbon-cache-a/*.log 

И graphite webapp с помощью uwsgi + какой-либо web-сервер (например, nginx):

cp /opt/graphite/webapp/graphite/local_settings.py.example /opt/graphite/webapp/graphite/local_settings.py # в local_settings.py необходимо изменить SECRET_KEY и TIME_ZONE. /opt/graphite/bin/uwsgi --socket localhost:6001 --master --processes 4 --home /opt/graphite --pythonpath /opt/graphite/webapp/graphite --wsgi-file=/opt/graphite/conf/graphite.wsgi.example --daemonize=/var/log/graphite-uwsgi.log 

Настройки nginx:

graphite.conf

upstream graphite_upstream {     server 127.0.0.1:6001; }      server {     listen 8085;     server_name graphite.local;          location / {         include            uwsgi_params;         uwsgi_pass         graphite_upstream;              add_header 'Access-Control-Allow-Origin' '*';         add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';         add_header 'Access-Control-Allow-Headers' 'origin, authorization, accept';         add_header 'Access-Control-Allow-Credentials' 'true';              proxy_redirect     off;         proxy_set_header   Host $host;         proxy_set_header   X-Real-IP $remote_addr;         proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header   X-Forwarded-Host $server_name;     } } 

Остается установить только carbon-tagger (именно он заполняет базу индексов для graph-explorer) и настроить дублирующую отправку метрик в carbon-cache и carbon-tagger при помощи carbon-relay. Но к сожалению, carbon-tagger не умеет работать по протоколу pickle, а carbon-relay отдает данные только в таком формате. Поэтому необходимо установить drop-in замену carbon-relay от vimeo — carbon-relay-ng:

go get -d github.com/graphite-ng/carbon-relay-ng go get github.com/jteeuwen/go-bindata/... cd "/opt/go/src/github.com/graphite-ng/carbon-relay-ng" make cp carbon-relay-ng /opt/go/bin/carbon-relay-ng touch /opt/graphite/conf/carbon-relay-ng.ini cd /opt/graphite carbon-relay-ng conf/carbon-relay-ng.ini 

carbon-relay-ng.ini

instance = "default" listen_addr = "127.0.0.1:2013" admin_addr = "127.0.0.1:2014" http_addr = "127.0.0.1:8081" spool_dir = "spool" log_level = "notice" bad_metrics_max_age = "24h"      init = [      'addRoute sendAllMatch carbon-default  127.0.0.1:2003 spool=true pickle=false', # отправляем все в carbon-cache      'addRoute sendAllMatch carbon-tagger  127.0.0.1:2023 spool=true pickle=false'  # отправляем все в carbon-tagger ]      [instrumentation] graphite_addr = "" graphite_interval = 1000  

carbon-tagger

Демон carbon-tagger написан на Go и занимается отправкой индексов метрик в Elastic Search для последующего их использования в graph-explorer. Прежде всего на сервере необходимо установить java и Elastic Search. Установка carbon-tagger:

go get github.com/Vimeo/carbon-tagger go get github.com/mjibson/party go build github.com/Vimeo/carbon-tagger 

carbon-tagger.conf

[in] port = 2023 # сюда присылает метрики carbon-relay-ng      [elasticsearch] host = "esearch.local" port = 9200 index = "graphite_metrics2" flush_interval = 2 max_backlog = 10000 max_pending = 5000      [stats] host = "localhost" port = 2003 # сюда carbon-tagger будет отправлять собственные внутренние метрики (не метрики приложения) id = "default" flush_interval = 10 http_addr = "127.0.0.1:8123" 

Запуск carbon-tagger:

(cd /opt/go/src/github.com/Vimeo/carbon-tagger/; ./recreate_index.sh) # инициализация индексов в ES carbon-tagger -config="/opt/graphite/conf/carbon-tagger.conf" -verbose=true 

graph-explorer

И наконец, установка гвоздя программы:

pip install graph-explorer 

graph-explorer.conf

[graph_explorer] listen_host = 127.0.0.1 # локальный адрес, чтобы добавить HTTP Basic Auth через nginx listen_port = 8080 filename_metrics = metrics.json log_file = /var/log/graph-explorer/graph-explorer.log      [graphite] url_server = http://localhost url_client = http://graphite.local:8085 # адрес graphite webapp 

nginx/graph-explorer.conf

server {     listen 80;     server_name metrics.yourproject.net;          location / {         auth_basic           "Who are you?";         auth_basic_user_file /etc/nginx/.htpasswd;         proxy_pass http://localhost:8080;     } } 

Запуск graph-explorer:

mkdir /var/log/graph-explorer run_graph_explorer.py /opt/graphite/conf/graph_explorer.conf 

После этого веб-интерфейс graph-explorer будет доступен по адресу metrics.yourproject.net.

Вместо заключения

Хватит жить разрабатывать с закрытыми глазами, %habrauser%! Разворачивайте системы сбора метрик и делитесь занимательными графиками из ваших проектов! Спасибо за внимание!

ссылка на оригинал статьи http://habrahabr.ru/post/260753/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *