Принцип Прометея и анализ исходного кода

задняя часть Go GitHub API

Prometheus (далее Prom) — система мониторинга на основе Metrics, принадлежит CNCF (Cloud Native Computing Foundation) вместе с Kubernetes, стала основной системой мониторинга в горячей экосистеме Kubernetes, все больше и больше проектов (таких как Kubernetes и т. д.) и т. д.) добавили богатую встроенную поддержку Prom, что отражает признание сообщества со стороны.

Prom предоставляет общую модель данных и удобные интерфейсы сбора, хранения и запроса данных.При этом реализация на основе Go также значительно снижает затраты на эксплуатацию и обслуживание сервера.Можно использовать несколько отличных графических инструментов (таких как Grafana) для достижения дружественной графики и сигнализации.

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

Перейти клиент

Клиент Go реализует протокол данных Prom, определяет модель данных временных рядов и интерфейс для сбора данных мониторинга (анализ исходного кода основан наGitHub.com/Прометей/…).

Общий структурный анализ

Будь то Prom, извлекающий (pull) данные или клиент, активно отправляющий (push) данные, определение метрики можно получить из Collector.Схема UML на рисунке 1.1.1 описывает взаимосвязь между основными структурами и интерфейсами в Go-клиенте.

Рис. 1.1.1 UML-диаграмма клиента Go

Сначала взгляните на определение интерфейса Collector, как показано на рисунке 1.1.2.

Рисунок 1.1.2 Коллектор

Методы Describe и Collect в Collector — это функции без сохранения состояния, в которых Describe предоставляет все возможные списки описаний метрик. При регистрации (Register) или отмене регистрации (Unregister) Collector будет вызываться Describe для получения полного списка метрик для определения определений метрик. , в обработчике инструментов по адресу github.com/prometheus/client_golang/prometheus/promhttp список метрик также будет получен через Describe, а список меток будет проверен (InstrumentHandler поддерживает только код и метод с двумя пользовательскими метками); Collect может получать образцы данных и предоставлять их серверу Prom Server через HTTP-интерфейс. Кроме того, некоторые временные процессы, такие как пакетные задачи, могут передавать данные на шлюз отправки, а шлюз отправки предоставляет интерфейс получения, который здесь не описан.

Сбор данных клиентом в основном осуществляется для стандартных структур данных:

  • Счетчик: собирает монотонно возрастающие данные, такие как количество событий
  • Датчик: Измерьте текущее состояние, например количество подключений к базе данных.
  • Гистограмма: собирает случайные нормально распределенные данные, такие как задержка ответа.
  • Резюме: сбор случайных данных с нормальным распределением, аналогичный гистограмме.

Каждая стандартная структура данных также соответствует структуре Vec.Через Vec можно кратко определить набор метрик того же характера, а набор пользовательских меток/значений передается при сборе данных для получения конкретных метрик (счетчик/измеритель/ Histogram/Summary), и в конечном итоге будет реализована в базовой структуре данных, которая не будет здесь повторяться.

Счетчик и датчик

Базовая реализация Gauge и Counter — это совместно используемое внутри процесса число с плавающей запятой, которое реализовано на основе структуры значения, в то время как Counter и Gauge только инкапсулируют различные операции и логику проверки достоверности для этого общего числа с плавающей запятой.

Сначала посмотрите на реализацию функции Inc в Counter На рисунке 1.2.1 показана реализация функции Inc в структуре значения.

Рисунок 1.2.1 значение.Inc

При изменении общих данных в value.Add используется реализация «без блокировки». будет значительно улучшена по сравнению с реализацией с Mutex. На рис. 1.2.2 показаны результаты тестирования Go Benchmark, в которых сравнивается влияние на производительность «заблокированной» (с отложенной блокировкой или без нее) и «свободной от блокировки» реализации в многоядерных сценариях.

Рисунок 1.2.2 Результаты тестирования Go Benchmark

Обратите внимание, что на рисунке 1.2.2 были проведены две группы экспериментов для «заблокированной» реализации, и одна из них использовала отсрочку для снятия блокировки. производительность в многоядерном сценарии.

Другие операции в Counter и Gauge очень просты, поэтому я не буду вдаваться в подробности.

Histogram

Гистограмма реализует интерфейс Observer, который используется для получения распределения точек выборки от инициализации (перезапуска) состояния клиента до определенного момента времени Данные мониторинга часто должны подчиняться нормальному распределению.

Рисунок 1.3.1 Определение интерфейса наблюдателя

Давайте сначала рассмотрим реализацию метода Observe для сбора данных типа float64 через гистограмму (рис. 1.3.2).

Рисунок 1.3.2 гистограмма. Наблюдайте

Здесь счетчики, соответствующие каждому бакету, не являются взаимоисключающими, и сумма счетчиков бакетов должна быть равна общему счетчику, то есть устанавливается h.count == sum(h.counts). Однако для облегчения хранения и расчета сервером данные, собранные сервером, включаются вниз, что реализовано в histogram.Write (рис. 1.3.3).

Рисунок 1.3.3 Гистограмма. Реализация записи

На рис. 1.3.4 показан процесс сбора и организации данных с помощью гистограммы в виде таблицы.

Рисунок 1.3.4 Пример процесса сбора и сортировки данных гистограммы

Гистограмма также не блокируется на стороне клиента, потому что каждая точка выборки обновляет только счетчик (float64) в определенном сегменте, поэтому накладные расходы на производительность клиента существенно не меняются по сравнению со счетчиком и датчиком, который подходит для одновременного сбора данных с большим объемом данных. .

На рисунке 1.3.5 показаны стандартные настройки корзины гистограммы клиента Go, которые можно использовать для сбора времени отклика веб-сервисов.В практических приложениях обычно необходимо выбрать разумные корзины для объектов мониторинга, и корзины быть установлен в точках квантилей, обычно используемых в нормальном распределении.

Рисунок 1.3.5. Настройки сегментов гистограммы по умолчанию

Summary

Сводка является наиболее сложной из стандартных структур данных и используется для сбора выборочных данных, соответствующих нормальному распределению. Структура сводки клиента Go и гистограмма реализуют интерфейс наблюдателя (рис. 1.3.1).

Квантиль в сводке на самом деле представляет собой квантиль нормального распределения, как показано на рис. 1.4.1, сплошные кружки на рисунке представляют квантиль [0,025 0,25 0,50 0,75 0,975] соответственно, а квантиль 0,5 на рис. 2.1.10. выборочные данные точки равны 0, а выборочное значение 0,975-го квантиля равно 2, что означает, что большинство пиков выборочных данных имеют значение около 2.

Рисунок 1.4.1 Моделирование квантильной аппроксимации случайных данных с нормальным распределением

Поскольку клиентская реализация структуры Summary более сложна, чем другие структуры, давайте взглянем на определение структуры summary (рис. 1.4.2).

Рисунок 1.4.2. Краткое определение

Сводка аппроксимирует собранные данные с помощью нормального распределения, чтобы получить данные выборки соответствующего квантиля.Поток данных показан на рисунке 1.4.3.

Рисунок 1.4.3 Сводный поток данных

Далее давайте посмотрим на резюме.Наблюдение за реализацией.К рисункам 1.4.4 и 1.4.5 добавлены аннотации логики кода.

Рисунок 1.4.4. Резюме. Наблюдение за реализацией

Рисунок 1.4.5 Реализация summary.asyncFlush

Глядя на реализацию summary.Write, аннотации логики кода добавлены к рисунку 1.4.6.

Рисунок 1.4.6. Резюме. Реализация записи

Предложения по оптимизации интеграции

При интеграции клиента необходимо обратить внимание на влияние сбора данных мониторинга на производительность и надежность программы, а также на полноту данных, то есть собираемые данные должны полностью и корректно отражать состояние и изменения объекта мониторинга Автор предлагает следующие два пункта Идеи:

  • Определить «подходящие» наборы данных мониторинга для объектов мониторинга.«Подходящий» требует сортировки и уточнения всего объекта мониторинга на этапе рабочего проектирования, без введения избыточных данных мониторинга, и не должно быть слепых зон мониторинга.
  • Выберите разумную структуру данных в соответствии с реальной ситуацией с каждыми данными мониторинга.

Клиент Go предоставляет удобный API для интеграции уровня HTTP, но вы должны быть осторожны, чтобы не использовать устаревшие функции Instrument, определенные на github.com/prometheus/client_golang/prometheus (раздел комментариев на рис. 1.5.1). кроме того, будут введены дополнительные (обычно ненужные) данные мониторинга, которые не только отрицательно повлияют на производительность программы, но также могут привести к опасным гонкам (например, горутины, одновременно обращающиеся к логике заголовка при расчете размера запроса).

Рисунок 1.5.1 InstrumentHandler (устаревший)

Клиент Go предоставляет оптимизированный API в последующих версиях, а именно реализацию на github.com/prometheus/client_golang/prometheus/promhttp, которая определяет независимый InstrumentHandlerXXX для различных данных мониторинга обработчика HTTP (рис. 1.5.2), сохраняя гибкость набора данных мониторинга. и управляемость полностью позволяет избежать некоторых проблем, упомянутых на рис. 1.5.1.

Рисунок 1.5.2 InstrumentHandlerXXX в promhttp

Другая трудность состоит в том, чтобы выбрать гистограмму и сводку и дать разумную начальную конфигурацию в соответствии с реальным сценарием использования.

Histogram часто использует histogram_quantile для выполнения анализа данных.Функция histogram_quantile аппроксимирует верхнюю границу распределения данных выборки с помощью модели кусочно-линейной аппроксимации (как показано на рисунке 1.5.3), ошибка относительно велика, а красная кривая — фактическая выборка. распределение (нормальное распределение), Сплошной кружок — сегмент гистограммы (0,01 0,25 0,50 0,75 0,95).При решении значения выборки квантиля 0,9 два соседних сегмента (0,75, 0,95) используются для линейной аппроксимации.

Рисунок 1.5.3 histogram_quantile аппроксимирует нормальное распределение

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

Конечно, цена высокой сводной точности заключается в том, что к клиенту добавляются дополнительные вычислительные ресурсы, а в сводной структуре часто выполняются операции глобальной блокировки, что оказывает определенное влияние на производительность программ с высокой степенью параллелизма. Результат анализа гистограммы и сводки Операции Benchmark, Observe и Write имеют экспоненциальные различия, и вам необходимо делать выбор, основываясь на реальных сценариях применения.

Рисунок 1.5.4 Гистограмма и итоговый сравнительный анализ

PromQL

PromQL — это язык запросов в Prom, который предоставляет краткий синтаксис естественного языка для анализа и расчета данных временных рядов.

Выражение (Expression) — это часть, которая несет в себе логику вычисления данных. Точное понимание выражения помогает в полной мере использовать возможности расчета и анализа, предоставляемые promql. В этом разделе сначала сочетается относительно сложное выражение, чтобы представить процесс вычисления PromQL. Затем выполняется анализ исходного кода некоторых репрезентативных реализаций функций.

процесс расчета

Входные данные выражения PromQL представляют собой фрагмент текста, Prom проанализирует этот текст, преобразует его в объект структурированного синтаксического дерева, а затем реализует соответствующую логику вычисления данных, вот относительно сложное выражение в качестве примера:

  • sum(avg_over_time(go_goroutines{job="prometheus"}[5m])) by (instance)

Приведенное выше выражение можно разложить на три слоя снаружи внутрь:

  • sum(…) by (instance): последовательности сгруппированы по вертикали для объединения последовательностей (в том числе один и тот же экземпляр будет назначен группе)
  • avg_over_time(…)
  • go_goroutines{job="prometheus"}[5m]

Рабочий процесс вызова вычисления выражения запроса Prom Restful API показан на рисунке 2.1.1. Параметр шага, заданный при запросе данных, здесь представляет собой интервал, который задает интервал между двумя соседними точками в результате. момент времени и оператор, и получен вектор (вектор с той же меткой времени). Prom может преобразовывать разнородные (несовместимые временные метки) многомерные временные ряды в однородные (согласованные временные метки) многомерные временные ряды посредством вычислений.

Рисунок 2.1.1 Рабочий процесс вычисления выражения запроса Restful API

Сначала посмотрите на вычисление go_goroutines{job="prometheus"}[5m], которое является объектом MatrixSelector в определенный момент времени (рис. 2.1.2).

Рисунок 2.1.2 MatrixSelector вычисляет go_goroutines{job="prometheus"}[5m]

Здесь итератор — это интерфейс последовательного доступа к результатам скрининга последовательности.На рисунке 2.1.2 получен фрагмент исторических данных с определенного момента времени.Это двумерная матрица, а внешняя функция суммирует эти исторические данные. в вектор (рис. 2.1.3).

Стоит отметить, что многие функции (такие как скорость) необходимо передавать в матрицу, однако выход этих функций по-прежнему является вектором для определенного момента времени, что является лишь частью расчета при вычислении вектора в определенный момент времени.Просто исторические данные.

Рисунок 2.1.3 Реализация avg_over_time

Наконец, давайте посмотрим на реализацию ключевого слова sum.Обратите внимание, что sum не является функцией.На рис. 2.1.4 показан список всех ключевых слов.

Рисунок 2.1.4 Список ключевых слов

Полный синтаксис ключевого слова sum более сложен, и в этой статье вводится только sum(…) by (instance), приведенный в примере.

Рисунок 2.1.5 sum(…) по (экземпляру) реализации

Пока выводится результирующий вектор в определенный момент времени, а процесс вычисления всего выражения отображается в Excel, как показано на рис. 2.1.6.

Рисунок 2.1.6 sum(avg_over_time(go_goroutines{job="prometheus"}[5m])) по (экземпляру) процесса вычисления

PromQL имеет три очень простых принципа:

  • Результаты, возвращаемые любым PromQL, не являются исходными данными, даже если запрашивается конкретная метрика (например, go_goroutines), результаты не являются исходными данными.
  • Любая метрика потеряет метку __name__ после вычисления функции
  • Подпоследовательности имеют точно такую ​​же пару ключ-значение Label/Value (могут иметь разные __name__) для выполнения алгебраических операций.

Особое внимание уделяется некоторым, как описано в 2.1.1, точкам равноудаленного интервала времени, используемым PromQL в расчетах, результаты каждого момента времени интервала получаются с помощью некоторой формы оценки или аппроксимации с использованием близлежащих точек выборки, поэтому в Prom такие упоминания, как «113 событий какого-то рода произошли в 1:28:07», являются неточными, и все результаты вычислений PromQL содержат ошибки.

Интересно, что при выполнении алгебраических операций над многомерными временными рядами в Prom нет необходимости строго проверять согласованность матриц с обеих сторон, потому что PromQL будет обрабатывать алгебраические операции только между последовательностями с одинаковыми метками/значениями.Алгебраические операции выполняются над несвязанными метрика для иллюстрации основных принципов алгебраических операций.В некоторых системах с «базой данных» в качестве ядра, таких как influxdb, операции между таблицами участвуют как в сложности выражения, так и в производительности вычислений.

Рисунок 2.1.7 Алгебраические операции над последовательностями

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

Частичная реализация функции (функции)

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

delta/rate/increase

Та же логика расчета используется для дельты/скорости/увеличения (рис. 2.2.1), только параметры другие.

Рисунок 2.2.1 Ввод функции дельта/скорость/увеличение

Глядя на реализацию extrapolatedRate (рис. 2.2.2), приращение значения выборки в момент времени интервала оценивается на основе алгоритма линейной экстраполяции, а линейная интерполяция широко используется в реализации Prom. Основной принцип очень прост: вычислите наклон начала и конца выборки в диапазоне, а затем линейно удлините его до фактической временной точки интервала.

Рисунок 2.2.2 экстраполированная скорость

В частности, здесь упоминаются два параметра isCounter и isRate, где isCounter=true указывает на то, что данные должны гарантированно увеличиваться монотонно, при перезапуске клиента счетчика данные вернутся к нулю, и появятся немонотонно возрастающие данные , то isCounter может контролировать правильность данных или нет.Данные корректируются; isRate=true используется для усреднения данных в пределах диапазона выборки, а результат представляет собой приращение значения выборки (приращение второго уровня) в течение одной секунды в текущий момент времени.

Теперь, оглядываясь назад, параметры дельты/скорости/увеличения на рисунке 2.2.1 ясны (таблица 2.2.1).

Function

isCounter

isRate

delta

false

false

rate

true

true

increase

true

false

Видно, что когда дельта обрабатывает данные, она не предполагает, что данные монотонно увеличиваются (isCounter=false), что подходит для обработки данных Gauge, тогда как увеличение подходит для обработки данных Counter и получения приращений в пределах диапазона; rate подходит для обработки счетчика и получения диапазона в интервале приращений в секундах.

XXX_over_time

XXX_over_time реализует горизонтальную агрегацию данных в пределах диапазона, то есть определенное количество исторических данных в пределах диапазона используется для оценки значения текущей точки времени, где XXX может быть такими глаголами, как avg/sum/max/min, и находится в функции XXX_over_time на рис. 2.2.3.

Рисунок 2.2.3 Функции, задействованные в XXX_over_time

Поскольку разница между ними заключается только в методе расчета, когда данные в диапазоне агрегируются по горизонтали, я не буду вводить их здесь по одному, а лишь сосредоточусь на реализации avg_over_time (рис. 2.2.4).

Рисунок 2.2.4 avg_over_time

Основная логика avg_over_time реализована в aggrOverTime, см. рис. 2.2.5.

Рисунок 2.2.5 aggrOverTime

XXX_over_time часто используется для сглаживания данных и фильтрации выбросов в данных. avg_over_time — это обычное «скользящее среднее значение окна», которое реализовано как фильтр нижних частот при обработке сигналов.

histogram_quantile

Histogram_quantile (рис. 2.2.6) — одна из самых непонятных функций в Prom.Она может оценивать значение выборочных данных в определенном квантиле нормального распределения на основе оценки гистограммы (на самом деле оценивается верхняя граница, т. е. верхний предел).

Рисунок 2.2.6 histogram_quantile

Логика оценки квантилей реализована в функции BucketQuantile (рис. 2.2.7).

Рисунок 2.2.7. Квантиль ведра

Суммировать

Prom — типичная система мониторинга на основе метрики, а метрика — форма анализа многомерных временных рядов в инженерии. Kubernetes и Prometheus часто обсуждаются вместе в сообществе, и их философия разработки такая же, как у Kubernetes: оба предлагают стандарты или протоколы для конкретных проблем, предоставляют конечным пользователям простые в использовании интерфейсы и фокусируются на предоставлении ценности домена.

Сбор данных Prom в основном достигается с помощью модели вытягивания, которая активно извлекает данные от клиента, уменьшая зависимость объекта мониторинга от внешних систем.В соответствии с этой моделью объект мониторинга должен поддерживать только небольшой объем клиентских данных, поддерживая контролируемый и простая реализация, снижающая риск поддержки сложной логики на стороне клиента. Кроме того, Prom предоставляет Push Gateway для некоторых временных процессов, таких как пакетные задачи.Эти клиенты могут отправлять данные в Push Gateway, а затем Push Gateway предоставляет интерфейс извлечения для предоставления данных серверу Prom.

По сравнению с Prom, общие решения для мониторинга метрик (такие как реализация клиента метрик InfluxDB)GitHub.com/Дэй Кроули/go…) — это все push-модели, и клиенту необходимо поддерживать жизненный цикл выборочных данных (например, данные, которые долгое время не сохранялись успешно, нужно отбрасывать и т. д.), а также необходимо избегать возможная утечка ресурсов на стороне клиента при сборе и хранении данных.

Кроме того, PromQL является точкой разногласий и ярким пятном в Prom.Он обеспечивает удобный синтаксис, близкий к семантике данных временных рядов, и имеет богатую поддержку анализа данных временных рядов.Например,Prom рассматривает монотонно возрастающие данные такие как Counter.Перезапуск вызывает проблему обнуления данных.Многие функции в Prom отказоустойчивы к таким данным при расчете,что полностью прозрачно для анализа данных,что значительно повышает удобство использования.В то же время PromQL предоставляет histogram_quantile для оценки значения квантиля в соответствии с гистограммой.Поддержка вычислений Quantile позволяет вычислять квантили на стороне Prom, что может снизить дополнительную нагрузку на производительность со стороны клиента.

Короче говоря, дизайн модели данных Prom и интерфейса аналитических вычислений имеет хорошую согласованность и расширяемость. С одной стороны, модель сбора данных на основе запросов снижает сложность клиента и его зависимость от внешних систем, а с другой стороны, позволяет клиенту свободно расширяться. Напротив, многие системы мониторинга, основанные на модели push, реализуются Мгновенное расширение может вызвать узкие места в производительности на стороне сервера системы мониторинга, влияющие на всю систему, а простой интерфейс PromQL делает анализ сложных данных временных рядов интуитивно понятным. и многие проекты должны быть обработаны.Processing Prom был встроен, что снижает стоимость предварительной обработки данных.

Об авторе

Ян Юцянь, старший инженер-программист, отдел инфраструктуры FreeWheel. В настоящее время он в основном занимается исследованиями, разработками и продвижением сервисной инфраструктуры и контейнерной платформы. Технологии, вызывающие озабоченность и интерес, в основном включают Golang, Docker, Kubernetes и окружающие их экосистемы.

благодарныйСюй ЧуаньОбзор этой статьи.