1. Внутренняя архитектура Prometheus: Pull-модель и жизненный цикл метрики
Внутренняя архитектура Prometheus: Pull-модель и жизненный цикл метрики
В индустрии мониторинга долгое время доминировала парадигма, при которой приложения сами отчитывались о своем состоянии. Логи отправляются в Logstash, трейсы пушатся в Jaeger, а классические системы вроде StatsD или InfluxDB пассивно слушают сетевой порт, ожидая, когда микросервисы пришлют им поток метрик. Когда инженеры SoundCloud создавали Prometheus, они пошли против устоявшегося стандарта и заложили в основу жесткую Pull-модель: система мониторинга сама ходит к приложениям и забирает данные. Это архитектурное решение определило не только то, как мы пишем экспортеры, но и то, как расследуются сложнейшие инциденты на стыке сети и инфраструктуры.
Фундаментальный выбор: почему Pull, а не Push
Чтобы понять внутреннюю логику Prometheus, необходимо разобрать инженерные компромиссы между моделями Push (отправка) и Pull (опрос).
В Push-модели инициатором выступает приложение. Оно содержит логику агрегации и таймеры, по которым открывает соединение с сервером мониторинга и сбрасывает накопленные данные.
В Pull-модели приложение абсолютно пассивно. Оно лишь хранит текущее состояние метрик в оперативной памяти и выставляет их наружу через легковесный HTTP-сервер (обычно на эндпоинте /metrics). Prometheus, руководствуясь собственной конфигурацией, регулярно делает HTTP GET запросы к этому эндпоинту.
!Сравнение архитектур Pull и Push
Выбор в пользу Pull-модели решает три критические проблемы надежности крупных систем:
Защита от перегрузки (Backpressure). В Push-модели сервер мониторинга уязвим перед собственными клиентами. Если из-за ошибки конфигурации или бага тысяча микросервисов начнет отправлять метрики в сто раз чаще, сервер мониторинга захлебнется в трафике (DDoS-атака собственной инфраструктурой) и упадет ровно в тот момент, когда он нужен больше всего. В Pull-модели Prometheus полностью контролирует объем входящих данных. Если система не справляется, она просто увеличивает интервал опроса. Мы теряем гранулярность данных, но ядро мониторинга выживает и продолжает показывать общую картину.
Явное обнаружение отказов. В White-box мониторинге критически важно отличать ситуацию «сервис работает, но нет запросов» от «сервис завис и не отвечает». При Push-модели отсутствие метрик — это тишина, которую сложно интерпретировать. При Pull-модели Prometheus ожидает ответа в заданный таймаут. Если ответа нет, Prometheus генерирует синтетическую метрику . Это позволяет мгновенно отличить сетевой сбой или зависание процесса от нормального простоя.
Децентрализация конфигурации. В Push-архитектуре каждому микросервису нужно знать адрес сервера мониторинга (или балансировщика). При изменении топологии мониторинга приходится обновлять конфигурацию всех клиентов. В Pull-архитектуре приложения ничего не знают о Prometheus. Prometheus сам узнает о приложениях через механизмы Service Discovery (например, опрашивая API Kubernetes), что делает инфраструктуру приложений независимой от инфраструктуры наблюдения.
Внутреннее устройство узла Prometheus
Prometheus — это не просто база данных временных рядов (TSDB). Это самодостаточный комбайн, который объединяет в одном бинарном файле несколько сложных подсистем.
!Внутренние компоненты Prometheus
Архитектурно процесс Prometheus делится на три основных блока:
/metrics.Важно понимать, что эти подсистемы работают асинхронно. Retrieval не ждет, пока кто-то сделает запрос через PromQL, а PromQL-движок читает данные, которые TSDB уже успела структурировать. Эта изоляция позволяет интерфейсу оставаться отзывчивым даже при тяжелой нагрузке на подсистему сбора.
Жизненный цикл метрики: от приложения до диска
Чтобы эффективно расследовать аномалии на дашбордах (например, почему график прерывается или показывает неверные пики), нужно пошагово проследить путь одной точки данных.
Шаг 1: Экспозиция в приложении
Сбор начинается за пределами Prometheus. Клиентская библиотека (клиент Prometheus) внутри вашего приложения резервирует участок оперативной памяти. Когда в коде происходит событие (например, обработан HTTP-запрос), библиотека инкрементирует счетчик в памяти.При обращении к /metrics библиотека мгновенно формирует текстовый ответ в формате Prometheus. Формат предельно прост и читается человеком:
http_requests_total{method="GET", status="200"} 1053
Здесь имя метрики и набор лейблов однозначно идентифицируют временной ряд, а 1053 — это текущее значение на момент запроса. Никаких временных меток (timestamps) приложение по умолчанию не отдает.
Шаг 2: Scrape-цикл
Подсистема Retrieval инициирует TCP-соединение и отправляет HTTP GET запрос. Здесь вступают в игру два критических параметра конфигурации:Если приложение отвечает за 2 секунды, Prometheus получает текстовый блок. Именно в этот момент — момент получения ответа сервером Prometheus — к данным прикрепляется серверный timestamp.
> Назначение временной метки самим сервером Prometheus решает проблему рассинхронизации часов (Clock Drift) на тысячах серверов в инфраструктуре. Даже если NTP на целевом сервере сломан, временной ряд в TSDB будет консистентным.
Шаг 3: Ingestion и Write-Ahead Log (WAL)
Полученные данные передаются в TSDB. Запись сразу на жесткий диск для каждой метрики убила бы любую дисковую подсистему из-за огромного количества случайных операций ввода-вывода (IOPS). Поэтому Prometheus использует концепцию Head Block — блока, который находится исключительно в оперативной памяти (RAM).Данные записываются в Head Block, что делает их мгновенно доступными для PromQL-запросов. Но хранение только в RAM несет риск потери данных при падении процесса (OOM Killer или перезагрузка сервера). Для защиты от потерь используется Write-Ahead Log (WAL).
Одновременно с записью в память, сырые данные последовательно (sequential write) дописываются в файл WAL на диске. Последовательная запись работает на порядки быстрее случайной. Если Prometheus упадет, при старте он прочитает WAL и полностью восстановит Head Block в памяти.
!Анимация жизненного цикла метрики: Scrape, WAL, TSDB
Шаг 4: Compaction (Сжатие и запись на диск)
Каждые два часа (по умолчанию) данные из Head Block замораживаются. TSDB берет этот двухчасовой срез, применяет мощные алгоритмы сжатия (Gorilla compression, позволяющая сжать одну точку данных до 1.37 байта) и формирует неизменяемый (immutable) блок на диске. После успешного создания блока на диске, старый WAL удаляется, а память освобождается для новых данных.Экзотические кейсы и подводные камни Pull-модели
Глубокое понимание описанного цикла позволяет SRE-инженеру объяснять странное поведение метрик, которое часто выглядит как «магия» или баг системы мониторинга.
Проблема Staleness (Устаревание данных)
Представьте ситуацию: под в Kubernetes масштабировался вниз (Scale Down) и был удален. Prometheus пришел за метриками, но эндпоинта больше нет. Что должно отображаться на графике трафика этого пода?В наивных системах мониторинга последнее известное значение могло бы тянуться бесконечно (плоская линия). В Prometheus реализован механизм обработки устаревания (Staleness). Если цель исчезает из Service Discovery или перестает отвечать, Prometheus не оставляет временной ряд «висеть». В момент следующего неудачного scrape-цикла TSDB записывает специальный маркер stale.
Движок PromQL, встречая маркер stale, понимает, что ряд завершен, и график в Grafana обрывается ровно в момент смерти пода. Однако, если таймаут превышен из-за перегрузки сети, а не из-за удаления пода, маркер stale не ставится сразу — Prometheus ждет до 5 минут (по умолчанию), прежде чем объявить ряд прерванным. Это спасает графики от «мигания» при кратковременных сетевых потерях.
Конфликт метрики "up" и неявных отказов
Мы упоминали, что метрикаup == 1 означает успешный сбор, а up == 0 — неудачный. Но здесь кроется частая ловушка для инженеров.Если ваше приложение зависло в бесконечном цикле (Deadlock) на уровне бизнес-логики, но фоновый поток, обслуживающий /metrics, продолжает работать, Prometheus успешно соберет данные. Метрика up будет равна 1. Инфраструктурные дашборды будут зелеными, хотя сервис фактически мертв. Это классическое проявление «арбузного мониторинга».
Метрика up гарантирует лишь доступность HTTP-сервера экспортера, но не работоспособность самого приложения. Для решения этой проблемы продвинутые экспортеры реализуют паттерн глубокой проверки: при обращении к /metrics они делают легковесный пинг к пулу соединений базы данных или внутренним очередям, и только если бизнес-ядро живо, отдают HTTP 200. Если ядро висит — отдают HTTP 500, что заставляет Prometheus зафиксировать неудачный scrape и перевести up в 0.
Пределы применимости Pull-модели
Pull-архитектура не универсальна. Она начинает ломаться в двух специфических сценариях:Для таких граничных случаев экосистема предоставляет инструмент Pushgateway — промежуточный кэш, в который краткосрочные скрипты могут пушить метрики, а Prometheus затем забирает их по Pull-модели. Однако использование Pushgateway для постоянно работающих сервисов считается антипаттерном, так как это возвращает нас к проблемам Push-модели (потеря контроля над потоком данных и маскировка отказов).
Переход от пассивного приема метрик к активному их сбору меняет саму суть работы системы наблюдения. Prometheus не просто хранилище — это активный участник инфраструктуры, который непрерывно зондирует окружение. Понимание того, как именно он управляет соединениями, формирует временные метки и защищает данные в оперативной памяти через WAL, дает инженеру возможность строить отказоустойчивые дашборды и точно интерпретировать разрывы на графиках во время масштабных аварий.