Как экспортёры (exporters) отдают метрики для Prometheus?

«Как экспортёры (exporters) отдают метрики для Prometheus?» — вопрос из категории Мониторинг и логирование, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Экспортёры — это ключевые агенты в стеке мониторинга на основе Prometheus. Они работают по принципу pull-модели: не отправляют данные сами, а предоставляют их по запросу.

Механизм работы:

  1. Сбор метрик: Экспортёр (например, node_exporter для хоста, nginx-exporter для веб-сервера) запускается как демон/контейнер рядом с целевым приложением или системой. Он периодически опрашивает его через:

    • Нативные API (Kubernetes API, AWS CloudWatch)
    • Системные вызовы (/proc, /sys в Linux)
    • Лог-файлы
    • Базы данных
    • Специфичные протоколы (SNMP, JMX).
  2. Предоставление метрик: Экспортёр открывает HTTP-эндпоинт (обычно на порту 9100, 9113 и т.д.) по пути /metrics. Когда Prometheus-сервер делает GET-запрос на этот эндпоинт, экспортёр возвращает ответ в текстовом формате Prometheus.

Пример ответа /metrics:

# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 100000.5
node_cpu_seconds_total{cpu="0",mode="system"} 5000.2
node_cpu_seconds_total{cpu="1",mode="idle"} 99900.7

# HELP http_requests_total Total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="POST",handler="/api",status="200"} 1234
http_requests_total{method="GET",handler="/health",status="200"} 56789

Практическая реализация (на Go): Большинство официальных экспортёров написаны на Go с использованием библиотеки prometheus/client_golang.

package main

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    requestsTotal = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "myapp_http_requests_total",
            Help: "Total HTTP requests.",
        },
        []string{"method", "path", "code"},
    )
)

func init() {
    prometheus.MustRegister(requestsTotal)
}

func main() {
    // Инкрементируем метрику в обработчике запросов
    requestsTotal.WithLabelValues("GET", "/api", "200").Inc()

    // Регистрируем handler для Prometheus
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}

В инфраструктуре: Я настраиваю Prometheus через scrape_configs в prometheus.yml на регулярный опрос (scrape) всех эндпоинтов экспортёров. Для динамических сред (Kubernetes) использую Service Discovery для автоматического поиска целей.