Как-то мне предстояло разобраться с метриками для нашего API, как всегда (нет времени?!) дописать позже — очень сложно и ещё не внедрили — значит пора внедрять. После некоторых скитаний в сети, самой популярной системой мониторинга, как мне показалось, был Prometheus.  При помощи Prometheus мы можем отслеживать различные ресурсы компьютера, такие как: память, загрузка процессора, диска, сети. Также нам может быть важно посчитать количество обращений к методам нашего API или измерить время их выполнения, ведь чем больше нагрузка на систему, тем дороже время её простоя. И тут нам на помощь приходит Prometheus. В данной статье приводятся, как мне кажется, основные моменты для понимания работы Prometheus и для добавления сбора метрик в API. Поэтому начнём с самого банального, с небольшого описания. Prometheus является системой с открытым исходным кодом и Time Series СУБД, написанный на Go и разработанной в компании SoundCloud. У него есть официальная документация и поддержка таких языков как: Go, Java или Scala, Python, Ruby. Есть неофициальная поддержка для других языков, таких как: C#, C++, C, Bash, Lua for Nginx, Lua for Tarantool и другие, весь список приведён на официальном сайте Prometheus. Все сервисы Prometheus доступны как образы Docker на Docker Hub или Quay.io. Запуск Prometheus осуществляется командой docker run -p 9090:9090 prom/prometheus, которая запускает его с дефолтной конфигурацией и устанавливает для него порт 9090. После чего UI Prometheus будет доступен по адресу localhost:9090. Prometheus представляет собой систему мониторинга, включающую в себя различные инструменты для настройки мониторинга приложений (конечных точек) при использовании HTTP-протокола. При соединении с Prometheus HTTP API не поддерживает "basic auth". Если требуется применить базовую аутентификацию для соединения с Prometheus, рекомендуется использовать Prometheus в сочетании с обратным прокси-сервером и применять аутентификацию на уровне прокси. Вы можете использовать любой обратный прокси-сервер с Prometheus. Основные компоненты Prometheus: Объекты, c которыми работает Prometheus, называются метриками, получаемыми от целевых объектов или через Pushgateway, или через Exporters. При сборе метрик используются несколько способов их передачи: Таким образом, все полученные метрики будут сохранены Prometheus в базе данных с указанием временных меток. Конфигурация Конфигурация Prometheus осуществляется при помощи флагов командной строки и файлов конфигурации, представленных в YAML-формате. Флаги командной строки позволяют настраивать неизменяемые параметры, такие как: пути, объемы данных, хранящиеся на диске и в памяти и т.д. Файл конфигурации позволяет настраивать всё, что связано с заданиями (jobs) и настройкой загружаемых yaml-файлов правил. Всё прописывается в глобальном файле конфигурации, он позволяет задать общие настройки для всех и выделить настройки для различных секций конфигураций в отдельности. Настройка целевых объектов, которые опрашивает Prometheus, осуществляются в файле конфигурации в секции scrape_configs. Prometheus может перезагружать файлы конфигурации во время работы, если новая конфигурация невалидна, то она не будет применена. Перезагрузка файла конфигурации запускается отправкой команды SIGHUP Prometheus или отправкой запроса HTTP POST на /-/reload, при условии, что установлен флаг --web.enable-lifecycle. Это также перезагрузит все настроенные файлы правил. Какие типы данных используются Prometheus хранит пользовательскую многомерную модель данных и использует язык запросов для многомерных данных, называемый PromQL. Prometheus хранит данные в виде временных рядов, он поддерживает несколько вариантов хранения: Сохраняемый временной ряд определяется метрикой и метаданными в виде пар «ключ-значение», хотя, при необходимости, имя метрики может не использоваться и сама метрика будет состоять только из метаданных. Временной ряд можно формально определить как <имя метрики>{<метаданные>}. Ключ — <имя метрики>{<метаданные>} — что мы измеряем, а значение — фактическая величина в виде числа с типом float64 (Prometheus поддерживает только этот тип). В описании ключа присутствуют метаданные (labels), описываемые также парами «ключ-значение»: <имя метки>="<значение метки>",<имя метки>="<значение метки>",... При хранении метрик используются следующие типы данных: Как сохраняются данные? Prometheus рекомендует "отдавать" 2/3 оперативной памяти под работающее приложение.
Для хранения данных в памяти Prometheus использует файлы, называемые chunk, для каждой метрики свой файл. Все файлы chunk иммутабельны, кроме последнего, в который пишутся данные. Новые данные сохраняются в chunk и каждые 2 часа фоновый поток объединяет данные и записывает их на диск. Каждый двухчасовой блок состоит из каталога, содержащего один или несколько файлов chunk, которые содержат все выборки временных рядов для этого промежутка времени, а также файл метаданных и индексный файл (который индексирует названия метрик и метки для временных рядов в файлах chunk). Если в течение одного часа Prometheus не пишет данные в chunck, то он будет сохранён на диск и будет создан новый chunck для записи данных. Максимальный срок хранения данных в Prometheus составляет ~21 день. Т.к. размер памяти фиксирован, производительность записи и чтения системы будет ограничена этим объемом памяти. Объем памяти PTSDB определяется минимальным периодом времени, периодом сбора и количеством временных метрик. Также в Prometheus реализован механизм WAL для предотвращения потери данных. Write ahead log (WAL) сериализует запоминаемые операции на постоянном носителе в виде файлов журнала. В случае сбоя файлы WAL могут быть использованы для восстановления базы данных до ее согласованного состояния путем восстановления из журналов. Файлы журнала хранятся в wal-каталоге в сегментах 128 МБ. Эти файлы содержат необработанные данные, которые еще не были сжаты, поэтому они значительно больше обычных файлов фрагментов. Prometheus будет хранить как минимум 3 файла журнала, однако серверы с высоким трафиком могут видеть более трех файлов WAL, поскольку ему необходимо хранить не менее двух часов необработанные данные. Результатом использования WAL является значительное уменьшение количества запросов записи на диск, т.к. в записи на диск нуждается только файл журнала, а не каждый фрагмент данных, изменённый в результате операции. Файл журнала записывается последовательно и таким образом затраты на синхронизацию журнала намного меньше, чем затраты на запись фрагментов с данными. Prometheus сохраняет периодические контрольные точки, которые по умолчанию добавляются каждые 2 часа путем сжатия журналов за прошедший период и сохранения их на диск. Все контрольные точки хранятся в одном каталоге с именем checkpoint.ddd, где ddd является числом, монотонно увеличивающимся. Поэтому, при восстановлении после сбоя, он может восстановить контрольные точки из каталога контрольных точек с указанием порядка (.ddd).
С помощью записи журналов WAL поддерживается возврат к любой контрольной точке, для которой доступен журнал данных. Что получилось у нас на практике? При добавлении в проект (.Net Framework) для сбора метрик мы использовали пакет Prometheus.Client.3.0.2. Для сбора метрик в проект были добавлены необходимые методы и классы, позволяющие хранить метрики, пока они не будут получены Prometheus. Первоначально был определён интерфейс IMetricsService, содержащий методы таймера для измерения времени работы методов: Добавляем класс MetricsService, который реализует интерфейс IMetricsService и временно хранит метрики. Теперь мы можем использовать наш класс для сохранения метрик, которые мы планируем собирать, в методах Application_BeginRequest, Application_Error, Application_EndRequest. В классе Global.cs добавляем сбор метрик в вышеуказанные методы. Добавляем новый контроллер, который будет являться контрольной точкой для отправки метрик нашего API в Prometheus: Последним шагом будет являться настройка конфига Prometheus для сбора метрик в секции scrape_configs, после чего мы можем увидеть собираемые метрики уже в UI Prometheus или Grafana. Ключевые функции, которые нам были интересны в Prometheus: Многомерная модель данных: метрики и метки.
Гибкий язык запросов PromQL. В одном и том же операторе запроса можем использовать такие операции, как умножение, сложение, конкатенация и др.; могут выполняться с несколькими метриками.
Собирает данные на основе HTTP, используя метод pull.
Совместим с методом push через Pushgateway.
Существует возможность собирать метрики с других приложений через Exporters.
Предоставляет механизм, предотвращающий потерю данных.
Поддерживает различное графическое представление данных.