Современный мониторинг: Архитектура Prometheus и Grafana

Глубокое погружение в проектирование систем наблюдаемости на основе метрик. Курс охватывает путь от базовых концепций TSDB до построения отказоустойчивых федеративных структур и продвинутой визуализации для Senior-позиций.

1. Философия Pull-модели и архитектурные компоненты экосистемы Prometheus

Философия Pull-модели и архитектурные компоненты экосистемы Prometheus

В 2012 году инженеры платформы SoundCloud столкнулись с архитектурным тупиком. Их монолитное приложение распадалось на сотни микросервисов, которые постоянно перезапускались, масштабировались и перемещались между серверами. Традиционные системы мониторинга, такие как Nagios и StatsD, не справлялись: конфигурации устаревали быстрее, чем применялись, а центральные серверы сбора метрик падали под шквалом входящих TCP-соединений от тысяч новых контейнеров. Ответом на этот кризис стал Prometheus — система, которая перевернула подход к мониторингу, отказавшись от ожидания данных в пользу их активного извлечения.

Чтобы проектировать отказоустойчивые системы наблюдаемости уровня Senior, недостаточно знать синтаксис конфигурационных файлов. Необходимо понимать фундаментальную разницу в паттернах доставки телеметрии и то, как архитектура Prometheus решает проблемы динамических инфраструктур.

Парадигма доставки данных: Push против Pull

Исторически большинство систем мониторинга (Zabbix, Telegraf/InfluxDB, StatsD) строились на Push-модели. В этой парадигме на каждом целевом узле устанавливается агент. Агент собирает локальные метрики, устанавливает сетевое соединение с центральным сервером мониторинга и «проталкивает» (push) данные в него.

В Pull-модели, которую исповедует Prometheus, вектор инициативы инвертирован. Целевое приложение или узел ничего не знает о сервере мониторинга. Оно лишь открывает HTTP-эндпоинт (обычно /metrics), по которому отдает свое текущее состояние в виде простого текста. Сервер Prometheus сам по расписанию опрашивает (scrape) список известных ему эндпоинтов и забирает данные.

!Сравнение архитектур Push и Pull моделей мониторинга

Разница кажется косметической, но на масштабе сотен серверов она кардинально меняет свойства системы.

| Характеристика | Push-модель (напр., Telegraf + InfluxDB) | Pull-модель (Prometheus) | | :--- | :--- | :--- | | Управление конфигурацией | Размазано по тысячам агентов. При изменении адреса сервера нужно обновить конфиги везде. | Централизовано на сервере мониторинга. Агенты (экспортеры) максимально тупые. | | Обнаружение сбоев | Если данных нет, сервер не знает причину: упал процесс, пропала сеть или агент завис? Требуются отдельные heartbeat-механизмы. | Сервер сам инициирует запрос. Если таймаут или отказ в соединении — сервер мгновенно фиксирует недоступность цели. | | Защита от перегрузки (DDoS) | При резком старте 10 000 контейнеров они одновременно бьют в сервер мониторинга, вызывая отказ в обслуживании. | Сервер сам контролирует параллелизм опросов. Он заберет данные тогда, когда у него будут ресурсы. | | Сетевая топология | Удобно, если целевые узлы за NAT или строгим файрволом (им нужен только исходящий доступ). | Требует маршрутизации от сервера мониторинга к каждому целевому узлу. |

Глубокие преимущества Pull-модели

Выбор Pull-архитектуры в Prometheus продиктован тремя инженерными потребностями современных инфраструктур.

1. Децентрализация отладки. В Push-модели данные улетают в черный ящик. Если разработчик хочет посмотреть метрики своего сервиса локально, ему нужно разворачивать весь стек мониторинга или перенастраивать агента на свой IP. В Pull-модели разработчику достаточно выполнить curl http://localhost:8080/metrics. Более того, можно запустить локальный бинарник Prometheus на ноутбуке и натравить его на production-эндпоинт для отладки, не внося никаких изменений в конфигурацию серверов.

2. Естественная высокая доступность (High Availability). Как зарезервировать сервер мониторинга в Push-модели? Нужно настраивать балансировщики нагрузки, учить агентов отправлять данные в два места одновременно или использовать сложные кластерные протоколы на стороне хранилища. В экосистеме Prometheus для обеспечения HA достаточно запустить два абсолютно независимых сервера Prometheus с одинаковой конфигурацией. Они оба будут ходить по одним и тем же эндпоинтам и собирать идентичные данные. Целевому сервису неважно, сколько серверов его опрашивают.

3. Истинный статус приложения (Up-state). Когда Prometheus пытается собрать метрики, он неявно выполняет Health Check. Если HTTP-запрос завершается ошибкой, Prometheus автоматически генерирует синтетическую метрику up{job="api"} = 0. Это гарантирует, что отсутствие данных — это не тишина в эфире, а конкретный зафиксированный сбой, на который можно повесить алерт.

Анатомия метрики и HTTP-экспозиция

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

Если сделать HTTP GET запрос к типичному экспортеру, ответ будет выглядеть так:

Здесь нет сложных JSON-структур. Каждая строка — это отдельный временной ряд (Time Series). Он состоит из имени метрики (http_requests_total), набора меток в фигурных скобках (method="post",code="200") и текущего значения (1027).

Метки (labels) — это основа многомерной модели данных Prometheus. Вместо того чтобы создавать иерархические имена вроде api.requests.post.200, Prometheus сохраняет плоскую структуру. Это позволяет впоследствии фильтровать и агрегировать данные по любому измерению (например, посчитать все 500-е ошибки по всем методам).

Важный нюанс: экспортер не хранит историю. Он хранит только текущее состояние счетчиков и датчиков в оперативной памяти. Временная метка (timestamp) обычно не передается экспортером — ее присваивает сам сервер Prometheus в момент получения данных.

Service Discovery: Нервная система мониторинга

Главная уязвимость Pull-модели — сервер должен знать IP-адреса всех целей. В статической инфраструктуре можно прописать их в конфигурационном файле prometheus.yml. Но в Kubernetes поды создаются и удаляются каждую минуту. IP-адреса эфемерны.

Решением выступает механизм Service Discovery (SD). Prometheus имеет встроенную интеграцию с десятками API: Kubernetes, Consul, AWS EC2, Azure, DNS.

Процесс выглядит так:

  • Prometheus подписывается на события API Kubernetes (например, через Kubernetes SD).
  • Как только запускается новый под с определенными аннотациями (например, prometheus.io/scrape: "true"), Kubernetes API уведомляет Prometheus.
  • Prometheus динамически добавляет IP-адрес нового пода во внутренний пул целей.
  • Начинается цикл опроса (Scrape loop).
  • !Цикл Service Discovery и сбора метрик в Prometheus

    Service Discovery не просто дает IP-адреса. Он обогащает метрики метаданными. Когда Prometheus забирает метрику у пода, он автоматически приклеивает к ней метки, полученные из Kubernetes API: имя пространства имен (namespace="production"), имя узла (node="worker-1") и лейблы самого пода. Это избавляет разработчиков от необходимости хардкодить инфраструктурные теги внутри кода приложения.

    Архитектура экосистемы: Компоненты и их роли

    Prometheus — это не один монолитный инструмент, а экосистема специализированных компонентов, каждый из которых решает строго одну задачу, следуя философии UNIX.

    !Полная схема компонентов экосистемы Prometheus

    1. Prometheus Server (Ядро)

    Сам сервер выполняет три основные функции, работающие в едином процессе: * Retrieval (Scraper): Движок, который реализует Service Discovery, планирует расписание опросов, распараллеливает HTTP-запросы к целям и обрабатывает таймауты. * TSDB (Time Series Database): Локальная база данных временных рядов. Полученные данные сжимаются в блоки (chunks) и записываются на диск. TSDB в Prometheus оптимизирована под колоссальную скорость записи (миллионы сэмплов в секунду) и использует append-only файлы. * HTTP Server: Предоставляет API для выполнения запросов на языке PromQL. Именно сюда обращается Grafana для отрисовки графиков.

    2. Exporters (Экспортеры)

    Что делать, если мы хотим мониторить ядро Linux, базу данных PostgreSQL или аппаратный маршрутизатор, которые не умеют отдавать метрики в формате Prometheus? Для этого существуют экспортеры — легковесные прокси-агенты.

    Экспортер устанавливается рядом с целевым сервисом. Он переводит внутреннее состояние системы в понятный Prometheus текстовый формат. * Node Exporter: Читает /proc и /sys в Linux, отдавая метрики CPU, памяти, дисков и сети. * Blackbox Exporter: Выполняет активные проверки (ICMP ping, HTTP GET, DNS запросы) внешних ресурсов. В этом случае Prometheus опрашивает Blackbox Exporter, передавая ему параметр — какой URL нужно проверить. * Специфичные экспортеры: MySQL Exporter, Nginx Exporter, JMX Exporter (для Java).

    3. Pushgateway (Исключение из правил)

    Pull-модель идеальна для демонов (постоянно работающих процессов). Но как мониторить cron-скрипт резервного копирования, который запускается ночью, работает 12 секунд и завершается? Prometheus с интервалом опроса в 30 секунд может просто не успеть его заметить.

    Для эфемерных задач (ephemeral jobs) создан Pushgateway. Это кэширующий сервис. Cron-скрипт перед завершением делает Push своих метрик в Pushgateway. Pushgateway сохраняет их в памяти и терпеливо ждет, пока Prometheus придет и заберет их по Pull-модели.

    Архитектурный нюанс: Pushgateway часто используют неправильно, пытаясь превратить Prometheus в Push-систему для постоянных сервисов. Это антипаттерн. Pushgateway не удаляет метрики автоматически. Если скрипт перестанет запускаться, Pushgateway будет вечно отдавать Prometheus старые значения, что сломает логику алертов.

    4. Alertmanager

    Prometheus сам вычисляет правила алертинга (например, node_memory_Active_bytes > 10GB). Но он не отправляет письма или сообщения в Slack. Как только условие выполняется, Prometheus отправляет сырой сигнал в Alertmanager.

    Alertmanager — это отдельный бинарник, который занимается маршрутизацией инцидентов. Его задачи: * Дедупликация: Если 100 серверов потеряли связь с базой данных, Alertmanager соберет 100 одинаковых алертов в один инцидент. * Группировка: Объединение алертов по датацентру или сервису. * Подавление (Inhibition): Если упал сетевой коммутатор, нет смысла отправлять алерты о недоступности 50 серверов, подключенных к нему. * Маршрутизация: Отправка критичных алертов в PagerDuty, а информационных — в Telegram-канал.

    5. Grafana

    Prometheus имеет встроенный веб-интерфейс, но он предназначен только для отладки PromQL-запросов. Для создания постоянных дашбордов, разграничения прав доступа и визуализации используется Grafana. Она подключается к Prometheus через HTTP API как обычный клиент.

    Сетевые ограничения и планирование емкости

    Pull-модель накладывает жесткие требования на сетевую топологию. Сервер Prometheus должен иметь прямую сетевую связность со всеми экспортерами. В сложных корпоративных сетях с DMZ и строгими правилами межсетевых экранов это становится проблемой. Безопасники неохотно открывают доступы из сети управления в изолированные контуры.

    В таких случаях применяется федерация (Federation) или иерархическая архитектура. В изолированном контуре ставится локальный (slave) Prometheus, который собирает метрики внутри своего сегмента. А глобальный (master) Prometheus делает Pull агрегированных данных уже с локального сервера.

    При проектировании архитектуры важно понимать математику нагрузки на сеть и диск. Объем данных, генерируемых системой мониторинга, зависит от интервала опроса (Scrape Interval).

    Оценить требуемую пропускную способность канала () в байтах в секунду можно по базовой формуле:

    где: * — количество целей (Targets, например, подов или серверов). * — среднее количество метрик, отдаваемых одной целью. * — средний размер одной строки метрики в байтах (обычно около 100-150 байт). * — интервал опроса в секундах (по умолчанию 15).

    Если у вас 2000 контейнеров, каждый отдает по 1000 метрик, то при интервале в 15 секунд мониторинг будет генерировать стабильный фоновый трафик около 15-20 МБ/с. Это необходимо учитывать при расчете стоимости трафика между зонами доступности в облаке.

    Архитектура Prometheus — это компромисс, смещающий сложность от тысяч агентов к единому центру. Понимание того, как Service Discovery связывает динамическую инфраструктуру с жестким циклом опроса, а экспортеры транслируют состояние систем в плоскую структуру временных рядов, является фундаментом. Без этого базиса невозможно написать эффективный запрос или спроектировать систему алертов, которая не будет будить инженеров по ночам из-за ложных срабатываний.

    2. Модель данных и язык запросов PromQL: от базовых селекторов до сложных агрегаций

    Модель данных и язык запросов PromQL: от базовых селекторов до сложных агрегаций

    Инженер настраивает алерт на высокую нагрузку и пишет запрос: вычисление среднего значения от метрики http_requests_total за пять минут. Алерт начинает срабатывать хаотично, то затапливая канал уведомлениями ночью, то молча игнорируя реальный сбой днем. Проблема кроется не в сети и не в приложении, а в фундаментальном непонимании модели данных Prometheus: http_requests_total — это счетчик, который всегда растет. Взять от него среднее значение напрямую — математический абсурд, равносильный попытке измерить скорость автомобиля путем усреднения показаний одометра.

    Чтобы писать надежные запросы и алерты, необходимо перестать мыслить категориями реляционных баз данных (строки и колонки) и перейти к парадигме многомерных временных рядов.

    Векторы и метки: анатомия временного ряда

    В основе модели данных Prometheus лежит временной ряд (Time Series). Каждый ряд однозначно идентифицируется комбинацией имени метрики и набора пар ключ-значение, которые называются метками (labels).

    Имя метрики описывает суть измеряемого свойства системы (например, node_memory_Active_bytes), а метки добавляют размерность. Если у вас 50 серверов, метрика node_memory_Active_bytes породит 50 независимых временных рядов, отличающихся меткой instance.

    Внутри базы данных (TSDB) каждое измерение (сэмпл) состоит всего из двух элементов:

  • Метка времени (timestamp) с точностью до миллисекунды.
  • Значение типа float64.
  • Prometheus не хранит строки, булевы значения или массивы внутри сэмплов. Любое состояние должно быть выражено числом с плавающей точкой. Если нужно передать текстовую информацию (например, версию приложения), она помещается в метки, а значением метрики становится 1.

    При выполнении запросов в PromQL (Prometheus Query Language) результаты возвращаются в одном из двух основных форматов:

    Мгновенный вектор (Instant Vector) — набор временных рядов, где каждый ряд содержит ровно один сэмпл, актуальный на заданный момент времени. Если вы отправите запрос node_memory_Active_bytes, вы получите мгновенный вектор — срез потребления памяти по всем серверам прямо сейчас.

    Вектор диапазона (Range Vector) — набор временных рядов, где каждый ряд содержит массив сэмплов за определенный интервал времени. Синтаксически это выражается добавлением временного окна в квадратных скобках: node_memory_Active_bytes[5m]. Этот запрос вернет все значения, собранные за последние 5 минут. Векторы диапазона нельзя напрямую отрисовать на графике в Grafana, они служат сырьем для функций, вычисляющих производные или агрегации (например, rate).

    Четыре типа метрик

    Хотя на уровне хранения TSDB все значения — это просто числа float64, на уровне клиентских библиотек (и логики обработки) метрики делятся на четыре типа. Понимание их семантики критично для выбора правильных функций PromQL.

    Gauge (Датчик)

    Самый простой тип. Значение может как увеличиваться, так и уменьшаться. Применяется для измерения текущего состояния: использование оперативной памяти, температура процессора, количество активных сессий, объем свободного места на диске. К Gauge применимы классические статистические функции: avg_over_time, max_over_time.

    Counter (Счетчик)

    Значение счетчика может только увеличиваться или сбрасываться в ноль (при перезапуске процесса). Примеры: общее количество обработанных HTTP-запросов, количество отправленных байт, число ошибок.

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

    !Визуализация работы функции rate при сбросе счетчика

    Функция rate() обладает встроенным механизмом защиты от сброса счетчика (counter reset). Если Prometheus видит, что новое значение счетчика меньше предыдущего, он понимает, что произошел перезапуск процесса, и прозрачно компенсирует этот провал, продолжая вычислять корректную скорость роста. Именно поэтому нельзя использовать rate() для метрик типа Gauge — естественное снижение значения Gauge будет ошибочно воспринято как рестарт, и график исказится.

    Histogram (Гистограмма)

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

    В Prometheus гистограммы кумулятивны. Корзины обозначаются меткой le (less than or equal — меньше или равно).

    !Структура кумулятивных бакетов гистограммы

    Если запрос выполнился за 0.2 секунды, он попадет в корзину le="0.5", но также он автоматически будет засчитан во все последующие корзины: le="1.0", le="5.0" и le="+Inf". Кумулятивность позволяет легко объединять гистограммы с разных серверов и вычислять процентили на стороне сервера мониторинга.

    Summary (Сводка)

    Как и гистограмма, измеряет распределение, но вычисляет процентили (например, 95-й процентиль времени ответа) непосредственно на клиенте (внутри приложения), отдавая готовое значение.

    Главный недостаток Summary — невозможность математически корректно агрегировать процентили с нескольких инстансов. Вы не можете взять среднее арифметическое от 99-х процентилей пяти серверов и получить 99-й процентиль кластера (это грубая статистическая ошибка). Поэтому в современных системах Summary используется редко, уступая место Histogram.

    Математика времени: rate(), irate() и increase()

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

    Функция rate(v range-vector) вычисляет среднюю скорость роста временного ряда в секунду за указанное окно. Формула расчета базируется на разнице между первым и последним сэмплом в окне. Если окно равно [5m], rate возьмет значение счетчика 5 минут назад, вычтет его из текущего значения и разделит на количество секунд в 5 минутах. Это сглаживает кратковременные всплески, показывая устойчивый тренд. rate() — стандарт де-факто для алертинга.

    Функция irate(v range-vector) (instant rate) также вычисляет скорость в секунду, но использует только два последних сэмпла в указанном временном окне. Если окно [5m], а метрики собираются каждые 15 секунд, irate проигнорирует 4 минуты и 30 секунд данных, взяв только два самых свежих значения. Это делает график невероятно отзывчивым и «дерганым», идеально показывая микро-спайки нагрузки. Однако использовать irate в правилах алертинга категорически нельзя: если спайк произошел между циклами вычисления алерта, irate его моментально забудет, и алерт не сработает.

    Функция increase(v range-vector) работает аналогично rate, но возвращает не скорость в секунду, а абсолютное приращение за указанное окно. increase(http_requests_total[1h]) покажет, сколько всего запросов пришло за последний час. Под капотом increase — это просто rate, умноженный на количество секунд в окне.

    Важный нюанс: все три функции интерполируют данные. Если крайние сэмплы не совпадают точно с границами временного окна, Prometheus экстраполирует значение. Поэтому increase от целочисленного счетчика может вернуть дробное число (например, ошибки). Это ожидаемое поведение системы, работающей с нерегулярными временными рядами.

    Агрегация: схлопывание размерностей

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

    Операторы агрегации (sum, avg, min, max, count) принимают мгновенный вектор и возвращают новый мгновенный вектор с меньшим количеством рядов.

    Для сохранения нужных размерностей используются модификаторы by (сохранить указанные метки) или without (удалить указанные метки, сохранив остальные).

    Вычисление суммарного количества запросов в секунду ко всему кластеру, сгруппированного по коду ответа: sum by (status) (rate(http_requests_total[5m]))

    Здесь порядок выполнения критичен. Сначала rate() вычисляет скорость роста для каждого индивидуального счетчика (каждого пода, каждого эндпоинта). Затем sum by (status) складывает эти скорости вместе, схлопывая метки instance, pod, method, и оставляя только status.

    Распространенная ошибка — поменять функции местами: rate(sum(http_requests_total)[5m]). Этот запрос выдаст ошибку, так как rate ожидает вектор диапазона (сырые данные из базы), а sum возвращает мгновенный вектор. Агрегировать можно только вычисленные скорости, но не сырые счетчики.

    Вычисление процентилей: histogram_quantile()

    Для оценки производительности системы среднее арифметическое (avg) часто бесполезно. Если 99 запросов выполнились за 10 мс, а один завис на 10 секунд, среднее время составит около 110 мс. Эта цифра не отражает ни опыт большинства пользователей, ни масштаб проблемы с зависшим запросом.

    Индустриальный стандарт — использование процентилей (квантилей). -й процентиль (p99) означает, что 99% запросов выполнились быстрее этого значения, а 1% — медленнее.

    В PromQL для этого используется функция histogram_quantile(φ, b). Она принимает желаемый квантиль (от 0 до 1) и агрегированную гистограмму.

    Полный запрос для вычисления p99 времени ответа по всем сервисам выглядит так: histogram_quantile(0.99, sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))

    Разберем этот сложный конструкт изнутри наружу:

  • http_request_duration_seconds_bucket[5m] — берем сырые данные бакетов за 5 минут.
  • rate(...) — вычисляем скорость приращения каждого бакета (сколько запросов в секунду падает в каждую корзину).
  • sum by (le, service) (...) — суммируем скорости бакетов со всех инстансов, сохраняя метку le (она обязательна для гистограммы) и разделяя результат по сервисам.
  • histogram_quantile(0.99, ...) — вычисляет итоговое значение в секундах.
  • Математика внутри histogram_quantile основана на линейной интерполяции. Если функция видит, что искомый 99-й процентиль находится где-то внутри бакета le="1.0", а предыдущий бакет был le="0.5", она предполагает, что значения внутри этого интервала (от 0.5 до 1.0) распределены равномерно, и высчитывает точную точку. Если реальные значения группируются у одного из краев бакета, интерполяция даст погрешность. Поэтому для точных процентилей важно правильно настраивать границы бакетов в коде приложения.

    Векторный матчинг: SQL JOIN в мире временных рядов

    Часто возникает необходимость произвести математическую операцию между двумя совершенно разными метриками. Например, разделить количество ошибок на общее количество запросов, чтобы получить процент отказа (Error Rate).

    В PromQL бинарные операторы (+, -, *, /) между двумя векторами требуют точного совпадения меток. Это называется One-to-One matching.

    Запрос rate(http_errors_total[5m]) / rate(http_requests_total[5m]) сработает только в том случае, если у обеих метрик абсолютно идентичный набор лейблов (например, instance="web-1", status="500"). Но у метрики ошибок может быть лейбл error_type, которого нет у метрики общих запросов. В таком случае векторы не совпадут, и результат будет пустым.

    Чтобы обойти это, используются модификаторы ignoring (игнорировать определенные лейблы при сравнении) или on (сравнивать только по указанным лейблам).

    Сложнее обстоит дело, когда кардинальность векторов не совпадает (Many-to-One или One-to-Many). Классический кейс: у вас есть метрика потребления памяти процессом process_resident_memory_bytes с лейблом instance. И есть информационная метрика app_version_info, которая всегда равна 1, но содержит полезные лейблы instance и version. Задача — вывести график потребления памяти, добавив к нему лейбл версии.

    В SQL это решалось бы через LEFT JOIN. В PromQL используется модификатор group_left.

    !Схема работы векторного матчинга с использованием group_left

    Синтаксис: process_resident_memory_bytes * on(instance) group_left(version) app_version_info

    В этом выражении:

  • * — умножение (значение памяти умножается на 1, оставаясь неизменным).
  • on(instance) — указывает, что векторы нужно связывать только по совпадению лейбла instance.
  • group_left(version) — указывает, что левый вектор (память) имеет бóльшую кардинальность, и к нему нужно «приклеить» лейбл version из правого вектора (app_version_info).
  • Векторный матчинг позволяет обогащать технические метрики бизнес-контекстом, не дублируя тяжелые метаданные в каждом сэмпле приложения.

    Переход от реляционной логики к векторной требует времени. Сила PromQL заключается в том, что язык заставляет инженера явно описывать поведение данных во времени (через окна [5m] и функции rate), не позволяя совершать грубые статистические ошибки, такие как прямое усреднение кумулятивных счетчиков. Понимание отличий между типами метрик и механизма векторного матчинга — это граница, отделяющая базовую эксплуатацию мониторинга от проектирования отказоустойчивых систем наблюдаемости.