Метрики: Prometheus в Go
Зачем знать: метрики — основа мониторинга и алертинга. Без них вы не узнаете о проблеме до жалобы клиента. Middle 1 Go-разработчик должен уметь экспортировать метрики через
prometheus/client_golang, не положить TSDB cardinality-бомбой, понимать различия Counter/Gauge/Histogram и читать PromQL. В 2026 Prometheus — де-факто стандарт, VictoriaMetrics — альтернатива.
Содержание
Заголовок раздела «Содержание»- Базовая концепция
- Как в Go (с примерами)
- Gotchas
- Best practices в production
- Вопросы на собесе
- Practice
- Источники
1. Базовая концепция
Заголовок раздела «1. Базовая концепция»Что такое Prometheus
Заголовок раздела «Что такое Prometheus»Prometheus — это pull-based time series database для мониторинга. Сервер периодически (по умолчанию каждые 15 секунд) опрашивает (scrape) HTTP endpoint /metrics ваших сервисов и сохраняет полученные числа во временные ряды.
Архитектура:
[ваш Go сервис] ← scrape /metrics → [Prometheus server] → [Grafana / Alertmanager]Каждый временной ряд (time series) — это уникальная комбинация metric name + labels:
http_requests_total{method="GET", path="/api/users", status="200"}Значение в каждый момент времени — число (float64).
Pull vs Push
Заголовок раздела «Pull vs Push»- Pull (Prometheus): сервер сам ходит за метриками. Преимущество: централизованная конфигурация, легко обнаружить мёртвый сервис (scrape failed), нет нужды в очереди.
- Push (StatsD, Graphite): клиент шлёт метрики на сервер. Полезно для коротких задач (batch jobs), где scrape невозможен → отсюда Pushgateway в Prometheus.
Метрические типы
Заголовок раздела «Метрические типы»Counter
Заголовок раздела «Counter»Монотонно растущее значение. Никогда не уменьшается (только сбрасывается при перезапуске).
Пример: http_requests_total, errors_total, bytes_sent_total.
PromQL для скорости: rate(http_requests_total[5m]) — запросов в секунду за окно 5 минут.
Текущее значение, которое может расти и падать.
Пример: goroutines_count, memory_usage_bytes, queue_size, temperature.
Histogram
Заголовок раздела «Histogram»Распределение значений по бакетам. Метрика автоматически создаёт:
metric_bucket{le="0.1"} 100(количество значений ≤ 0.1)metric_bucket{le="0.5"} 250metric_bucket{le="+Inf"} 300metric_sum— сумма всех значенийmetric_count— общее количество
Пример: http_request_duration_seconds, db_query_duration_seconds.
Квантили (p50, p95, p99) считаются на стороне Prometheus через histogram_quantile(0.99, rate(metric_bucket[5m])).
Summary
Заголовок раздела «Summary»Похож на histogram, но квантили предвычислены на клиенте (metric{quantile="0.95"} 0.123).
Минусы summary:
- Невозможно агрегировать квантили между инстансами (нельзя сложить p95 с двух подов).
- Дороже по CPU на клиенте (квантильный алгоритм).
- Бакеты histogram можно перестроить ретроспективно через PromQL.
В 2026 предпочитают Histogram + recording rules.
Recording rules
Заголовок раздела «Recording rules»Предвычисленные PromQL-выражения, сохраняемые как новые time series. Снижают нагрузку на запросы.
groups:- name: http rules: - record: instance:http_requests:rate5m expr: rate(http_requests_total[5m])Alerting rules
Заголовок раздела «Alerting rules»PromQL-условия, по которым отправляется alert в Alertmanager.
- alert: HighErrorRate expr: rate(errors_total[5m]) > 0.05 for: 10mSLI / SLO / SLA
Заголовок раздела «SLI / SLO / SLA»- SLI (Service Level Indicator) — метрика качества: latency p99, error rate, availability.
- SLO (Service Level Objective) — цель: p99 < 200ms, errors < 0.1%.
- SLA (Service Level Agreement) — контракт с клиентом (юридический документ).
Метрики Prometheus — основа SLI/SLO. Error budget = (1 − SLO) × time.
Методы наблюдения
Заголовок раздела «Методы наблюдения»- USE (Brendan Gregg) — для ресурсов: Utilization, Saturation, Errors.
- RED (Tom Wilkie) — для сервисов: Rate, Errors, Duration.
- The Four Golden Signals (Google SRE) — Latency, Traffic, Errors, Saturation.
2. Как в Go (с примерами)
Заголовок раздела «2. Как в Go (с примерами)»2.1 Установка
Заголовок раздела «2.1 Установка»go get github.com/prometheus/client_golang@latestВ 2026 актуальная версия — v1.20+.
2.2 Простейший экспортёр
Заголовок раздела «2.2 Простейший экспортёр»package main
import ( "net/http"
"github.com/prometheus/client_golang/prometheus/promhttp")
func main() { http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":2112", nil)}promhttp.Handler() экспортирует Go runtime метрики (GC, goroutines, memory) автоматически. Проверьте: curl localhost:2112/metrics.
2.3 Counter
Заголовок раздела «2.3 Counter»package main
import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" "net/http")
var ( requestsTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "path", "status"}, ))
func handler(w http.ResponseWriter, r *http.Request) { requestsTotal.WithLabelValues(r.Method, r.URL.Path, "200").Inc() w.Write([]byte("ok"))}
func main() { http.HandleFunc("/api", handler) http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":8080", nil)}promauto.NewCounterVec автоматически регистрирует метрику в дефолтном регистре. Без promauto пришлось бы вызывать prometheus.MustRegister(metric).
2.4 Gauge
Заголовок раздела «2.4 Gauge»var ( goroutineCount = promauto.NewGauge(prometheus.GaugeOpts{ Name: "goroutines_in_pool", Help: "Current number of goroutines in worker pool", }))
func work() { goroutineCount.Inc() defer goroutineCount.Dec() // работа}
// Или прямая установкаgoroutineCount.Set(42)2.5 Histogram
Заголовок раздела «2.5 Histogram»var ( requestDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request latency", Buckets: prometheus.DefBuckets, // [.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10] }, []string{"method", "path"}, ))
func middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) duration := time.Since(start).Seconds() requestDuration.WithLabelValues(r.Method, r.URL.Path).Observe(duration) })}prometheus.ExponentialBuckets(0.001, 2, 10) создаёт бакеты [0.001, 0.002, 0.004, ..., 0.512] — экспоненциальный шаг для измерения latency на широком диапазоне.
2.6 Custom registry
Заголовок раздела «2.6 Custom registry»По умолчанию promauto использует prometheus.DefaultRegisterer. Если нужен отдельный регистр (например, тесты):
reg := prometheus.NewRegistry()factory := promauto.With(reg)myCounter := factory.NewCounter(prometheus.CounterOpts{Name: "test"})handler := promhttp.HandlerFor(reg, promhttp.HandlerOpts{})2.7 HTTP middleware с метриками
Заголовок раздела «2.7 HTTP middleware с метриками»package middleware
import ( "net/http" "strconv" "time"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto")
type Metrics struct { requestsTotal *prometheus.CounterVec requestDuration *prometheus.HistogramVec inFlight prometheus.Gauge}
func NewMetrics(reg prometheus.Registerer) *Metrics { factory := promauto.With(reg) return &Metrics{ requestsTotal: factory.NewCounterVec(prometheus.CounterOpts{ Name: "http_requests_total", Help: "HTTP requests total", }, []string{"method", "path", "status"}), requestDuration: factory.NewHistogramVec(prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration", Buckets: prometheus.ExponentialBuckets(0.001, 2, 16), }, []string{"method", "path"}), inFlight: factory.NewGauge(prometheus.GaugeOpts{ Name: "http_in_flight_requests", Help: "Currently in-flight requests", }), }}
func (m *Metrics) Handler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { m.inFlight.Inc() defer m.inFlight.Dec()
start := time.Now() rw := &recorder{ResponseWriter: w, status: 200}
next.ServeHTTP(rw, r)
duration := time.Since(start).Seconds() // ВАЖНО: route, а не URL.Path — иначе cardinality bomb! route := getRoutePattern(r) // зависит от роутера: chi.RouteContext, gorilla.CurrentRoute m.requestsTotal.WithLabelValues(r.Method, route, strconv.Itoa(rw.status)).Inc() m.requestDuration.WithLabelValues(r.Method, route).Observe(duration) })}
type recorder struct { http.ResponseWriter status int}
func (r *recorder) WriteHeader(code int) { r.status = code r.ResponseWriter.WriteHeader(code)}
func getRoutePattern(r *http.Request) string { // chi: // if rctx := chi.RouteContext(r.Context()); rctx != nil { return rctx.RoutePattern() } return r.URL.Path}2.8 Метрики gRPC
Заголовок раздела «2.8 Метрики gRPC»import ( "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/prometheus" "google.golang.org/grpc")
srvMetrics := grpcprom.NewServerMetrics( grpcprom.WithServerHandlingTimeHistogram(),)reg.MustRegister(srvMetrics)
server := grpc.NewServer( grpc.UnaryInterceptor(srvMetrics.UnaryServerInterceptor()), grpc.StreamInterceptor(srvMetrics.StreamServerInterceptor()),)
// После регистрации всех сервисов:srvMetrics.InitializeMetrics(server)Экспортируются grpc_server_handled_total, grpc_server_handling_seconds_bucket и т.д.
2.9 Метрики БД
Заголовок раздела «2.9 Метрики БД»var ( dbQueryDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "db_query_duration_seconds", Help: "DB query duration", Buckets: prometheus.ExponentialBuckets(0.001, 2, 14), }, []string{"query"})
dbQueryErrors = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "db_query_errors_total", Help: "DB query errors", }, []string{"query", "code"}))
func (r *Repo) GetUser(ctx context.Context, id string) (*User, error) { const queryName = "GetUser" start := time.Now() defer func() { dbQueryDuration.WithLabelValues(queryName).Observe(time.Since(start).Seconds()) }() var u User err := r.db.QueryRowContext(ctx, "SELECT id, name FROM users WHERE id=$1", id).Scan(&u.ID, &u.Name) if err != nil { dbQueryErrors.WithLabelValues(queryName, classifyError(err)).Inc() return nil, err } return &u, nil}2.10 collectors.NewDBStatsCollector
Заголовок раздела «2.10 collectors.NewDBStatsCollector»Для database/sql:
import "github.com/prometheus/client_golang/prometheus/collectors"
reg.MustRegister(collectors.NewDBStatsCollector(db, "users_db"))Экспортирует go_sql_* метрики: открытые соединения, idle, wait_duration и т.д.
2.11 Custom collector
Заголовок раздела «2.11 Custom collector»Когда стандартные метрики не подходят:
type PoolCollector struct { pool *MyPool used *prometheus.Desc}
func NewPoolCollector(p *MyPool) *PoolCollector { return &PoolCollector{ pool: p, used: prometheus.NewDesc("pool_used", "used connections", nil, nil), }}
func (c *PoolCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.used}
func (c *PoolCollector) Collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(c.used, prometheus.GaugeValue, float64(c.pool.Used()))}
// reg.MustRegister(NewPoolCollector(pool))Collect вызывается при каждом scrape — отдавайте «фотографию» состояния.
2.12 Native histograms (Prometheus 2.40+)
Заголовок раздела «2.12 Native histograms (Prometheus 2.40+)»Sparse histograms с автоматическими бакетами:
hist := promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "...", NativeHistogramBucketFactor: 1.1, // ~10% resolution NativeHistogramMaxBucketNumber: 100, NativeHistogramMinResetDuration: time.Hour,}, []string{"path"})Меньше места в TSDB, более точные квантили на длинном диапазоне. Требует Prometheus 2.40+ и поддержки в Grafana 9.2+.
2.13 Тесты с метриками
Заголовок раздела «2.13 Тесты с метриками»import "github.com/prometheus/client_golang/prometheus/testutil"
func TestCounter(t *testing.T) { reg := prometheus.NewRegistry() c := promauto.With(reg).NewCounter(prometheus.CounterOpts{Name: "test"}) c.Inc() c.Inc()
expected := `# HELP test# TYPE test countertest 2` if err := testutil.GatherAndCompare(reg, strings.NewReader(expected), "test"); err != nil { t.Fatal(err) }}2.14 Pushgateway (для batch jobs)
Заголовок раздела «2.14 Pushgateway (для batch jobs)»import "github.com/prometheus/client_golang/prometheus/push"
err := push.New("http://pushgateway:9091", "my_batch_job"). Collector(myCounter). Push()Pushgateway хранит последний пуш до следующего, Prometheus скрейпит pushgateway. Не используйте для долго живущих сервисов — теряется time-series natural lifecycle.
2.15 VictoriaMetrics
Заголовок раздела «2.15 VictoriaMetrics»Совместима с Prometheus exposition format (тот же /metrics). Часто используется в РФ/CIS как drop-in замена с лучшей компрессией и vmagent для агрегации. Ваш Go-код не меняется.
3. Gotchas
Заголовок раздела «3. Gotchas»3.1 Cardinality bomb
Заголовок раздела «3.1 Cardinality bomb»// КАТАСТРОФАrequestsTotal.WithLabelValues(userID).Inc() // 10М уникальных user_id = 10М seriesКаждая уникальная комбинация labels — отдельный time series. Prometheus хранит их в памяти. Cardinality > 10М на инстанс — OOM.
Правило: количество уникальных значений каждой label < 100, в произведении < 10К на metric. Никогда не label-ить:
- user_id, email, request_id, trace_id (бесконечная cardinality)
- URL целиком (вместо этого —
route patternтипа/users/:id) - raw error message (классифицируйте:
code="timeout", неmsg="connection refused after 5s...")
3.2 Labels — типизация
Заголовок раздела «3.2 Labels — типизация»requestsTotal.WithLabelValues("GET", "/api", 200).Inc() // BAD: 200 — intWithLabelValues принимает ...string. int без конверсии не компилируется, но если у вас неявная конверсия (через fmt.Sprint) — каждый 200/201/202 создаст отдельную series.
Лучше группировать: status_class = "2xx", "4xx", "5xx".
3.3 Counter может уменьшиться (на ресет)
Заголовок раздела «3.3 Counter может уменьшиться (на ресет)»При рестарте сервиса counter обнуляется. PromQL rate() и increase() корректно обрабатывают reset (находят падение и считают, что был reset). Не пытайтесь delta() на counter — она не учитывает resets.
3.4 Histogram buckets — выбор критичен
Заголовок раздела «3.4 Histogram buckets — выбор критичен»Buckets: []float64{0.1, 0.5, 1, 5, 10} // BAD для latency 1-100msЕсли ваши latency 1-100ms, а первый бакет 100ms — все попадут в le=0.1 и квантили будут бесполезны.
Для HTTP latency:
Buckets: prometheus.ExponentialBuckets(0.001, 2, 16) // 1ms .. ~65sДля DB:
Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5}Подберите по своему профилю latency. Лучше изменить буферы один раз заранее, чем потом ломать историю.
3.5 Histogram не показывает outliers
Заголовок раздела «3.5 Histogram не показывает outliers»Если бакет [+Inf] единственный с большим counter, вы знаете, что были outliers, но не знаете, насколько. Включите summary или native histograms или просто добавьте бакет повыше.
3.6 Race на одной метрике
Заголовок раздела «3.6 Race на одной метрике»prometheus.Counter thread-safe. Но WithLabelValues — нет дешёвая операция (map lookup + mutex). В hot path делайте:
metric := requestsTotal.WithLabelValues("GET", "/api", "200") // один разfor ... { metric.Inc()}3.7 Промаху на /metrics
Заголовок раздела «3.7 Промаху на /metrics»Если ваш сервис не отвечает на scrape — Prometheus отмечает up{job="myservice"} 0. Делайте alerting:
- alert: ServiceDown expr: up == 0 for: 5m3.8 Конкурентная регистрация
Заголовок раздела «3.8 Конкурентная регистрация»promauto.NewCounter(...) падает (panic), если метрика с таким именем уже зарегистрирована. Это часто случается в тестах. Решение: отдельный prometheus.NewRegistry() на тест.
3.9 promhttp не показывает в scrape
Заголовок раздела «3.9 promhttp не показывает в scrape»Проверьте:
- handler установлен на правильный путь (
/metrics). - порт открыт.
- если используете chi/gin — handler должен быть зарегистрирован.
r := chi.NewRouter()r.Handle("/metrics", promhttp.Handler())3.10 Метрики и middleware-порядок
Заголовок раздела «3.10 Метрики и middleware-порядок»r.Use(metricsMiddleware) // BAD: status всегда 200, не firedr.Use(loggingMiddleware)Metrics-middleware должен быть первым (обернуть всё), чтобы видеть финальный статус после всех middleware.
3.11 Гранулярность scrape interval
Заголовок раздела «3.11 Гранулярность scrape interval»Дефолт — 15s. Если ставите 1s — TSDB взлетит по объёму. 15-30s — компромисс. Для бизнес-метрик 1m нормально.
3.12 ResetMetrics после теста
Заголовок раздела «3.12 ResetMetrics после теста»prometheus.DefaultRegisterer.Unregister(myCounter) // в TestMain teardownИначе следующий тест паникует на double-register.
4. Best practices в production
Заголовок раздела «4. Best practices в production»4.1 Naming convention
Заголовок раздела «4.1 Naming convention»<namespace>_<subsystem>_<name>_<unit>- Все nameless lowercase,
_как разделитель. - Counter — суффикс
_total. - Histogram —
_seconds,_bytes. - Gauge — без суффикса (или
_count,_size).
Примеры:
http_requests_totaldb_query_duration_secondsworker_pool_sizecache_hits_total,cache_misses_total
4.2 RED для каждого сервиса
Заголовок раздела «4.2 RED для каждого сервиса»Для любого RPC-сервиса (HTTP, gRPC) экспортируйте:
- Rate —
rate(http_requests_total[5m]). - Errors —
rate(http_requests_total{status=~"5.."}[5m]). - Duration —
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])).
4.3 USE для ресурсов
Заголовок раздела «4.3 USE для ресурсов»Для пулов, очередей, БД:
- Utilization — % use (
pool_used / pool_size). - Saturation — queue length (
pool_wait_queue). - Errors —
pool_errors_total.
4.4 Labels: low cardinality
Заголовок раздела «4.4 Labels: low cardinality»Допустимые labels:
method(GET/POST/…) — <10.statusилиstatus_class(2xx/4xx/5xx).route_pattern(/users/:id) — <1000.service,version,env— несколько.
Запрещённые labels:
user_id,email,phone,request_id,trace_id.error_message(raw).query_string.
4.5 Native histograms (с осторожностью)
Заголовок раздела «4.5 Native histograms (с осторожностью)»Если Prometheus 2.40+ и Grafana 9.2+, переходите на native histograms — меньше storage, лучше resolution. Но проверьте совместимость с alertmanager rules.
4.6 Default Go collectors
Заголовок раздела «4.6 Default Go collectors»import "github.com/prometheus/client_golang/prometheus/collectors"
reg := prometheus.NewRegistry()reg.MustRegister( collectors.NewGoCollector(collectors.WithGoCollections(collectors.GoRuntimeMetricsCollection)), collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),)Дают go_goroutines, go_memstats_*, process_cpu_seconds_total, process_resident_memory_bytes и десятки runtime-метрик.
4.7 Отдельный порт для /metrics
Заголовок раздела «4.7 Отдельный порт для /metrics»Не публикуйте /metrics на бизнес-порту:
go func() { http.ListenAndServe(":9090", promMux) // только metrics}()http.ListenAndServe(":8080", apiMux) // бизнес-APIВ K8s одновременно открыты, но в Service публикуете только бизнес-порт.
4.8 Recording rules для дорогих PromQL
Заголовок раздела «4.8 Recording rules для дорогих PromQL»- record: instance:http_requests:rate5m expr: rate(http_requests_total[5m])Dashboards используют precomputed series — меньше нагрузка на TSDB.
4.9 Service discovery
Заголовок раздела «4.9 Service discovery»Не хардкодьте scrape targets. В K8s используйте prometheus-operator с PodMonitor/ServiceMonitor или kubernetes_sd_configs. Это автоматически добавит/удалит таргеты при rollout.
4.10 Alerting
Заголовок раздела «4.10 Alerting»- alert: HighLatencyP99 expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 0.5 for: 10m labels: severity: warning annotations: summary: "p99 latency > 500ms"Алерты — for ≥ scrape interval × 3, чтобы избежать flapping.
4.11 Histogram + recording rules для квантилей
Заголовок раздела «4.11 Histogram + recording rules для квантилей»- record: service:request_duration_seconds:p99 expr: histogram_quantile(0.99, sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))Используйте в alertmanager/dashboard.
4.12 OpenMetrics format
Заголовок раздела «4.12 OpenMetrics format»Prometheus поддерживает OpenMetrics (расширение exposition format с _created timestamps). promhttp.HandlerFor(reg, promhttp.HandlerOpts{EnableOpenMetrics: true}) — включить.
4.13 Multi-tenant метрики
Заголовок раздела «4.13 Multi-tenant метрики»Если ваш сервис мульти-тенантный, не используйте tenant_id как label если их > 1000. Лучше — отдельный registry или агрегация в коллекторе.
4.14 Grafana дашборды как код
Заголовок раздела «4.14 Grafana дашборды как код»Храните JSON-дашборды в репозитории, деплойте через Grafana provisioning или Grafana Cloud API.
4.15 SLI/SLO
Заголовок раздела «4.15 SLI/SLO»- record: slo:availability:5m expr: sum(rate(http_requests_total{status!~"5.."}[5m])) / sum(rate(http_requests_total[5m]))Цель: slo:availability:5m > 0.999 для p99 за месяц.
5. Вопросы на собесе
Заголовок раздела «5. Вопросы на собесе»-
Чем pull-based отличается от push-based мониторинга? Pull (Prometheus): сервер скрейпит targets, легко обнаружить мёртвый сервис, целевая конфигурация на сервере. Push (StatsD): клиент шлёт, нужна очередь или Pushgateway для batch jobs.
-
Counter vs Gauge vs Histogram? Counter — монотонно растёт (requests_total). Gauge — текущее значение (memory). Histogram — распределение по бакетам (latency).
-
Почему Summary считается устаревшим? Квантили не агрегируются между инстансами, дороже CPU, нельзя пересчитать ретроспективно. Histogram +
histogram_quantileв PromQL — гибче. -
Что такое cardinality? Произведение уникальных значений всех labels метрики. Высокая cardinality → много time series → OOM/медленные запросы.
-
Почему нельзя label-ить user_id? Каждый user_id создаёт новую time series. 10М users = 10М series = OOM. user_id логировать, но не метрики.
-
Что делает
rate(metric[5m])? Среднюю скорость роста counter за окно 5 минут (per-second). Учитывает counter resets. -
Как вычислить p99 из histogram?
histogram_quantile(0.99, sum by (le) (rate(metric_bucket[5m]))). Не забудьтеby (le)— иначе квантиль усреднится по бакетам неверно. -
Что такое RED и USE? RED — Rate, Errors, Duration (для сервисов). USE — Utilization, Saturation, Errors (для ресурсов).
-
Что такое SLI/SLO/SLA? SLI — метрика (latency p99). SLO — цель (p99 < 200ms). SLA — контракт с клиентом (юридический).
-
Что такое Pushgateway? Промежуточный сервер для коротких задач (batch, CI/CD). Клиент пушит, Prometheus скрейпит pushgateway. Не для long-running сервисов.
-
Чем
promautoотличается отprometheus?promautoавтоматически регистрирует метрику вDefaultRegisterer. Без него —prometheus.MustRegister(metric)вручную. -
Что такое recording rule? Precomputed PromQL, сохраняемый как новая series. Снижает нагрузку на тяжёлые запросы.
-
Как добавить кастомную метрику для пула соединений? Реализовать
prometheus.Collectorинтерфейс (Describe+Collect), регистрировать черезMustRegister. -
Зачем
http_request_duration_seconds_bucketсуффиксle?le= “less than or equal”. Бакетle="0.5"содержит все наблюдения ≤ 0.5s. Кумулятивные. -
Что такое native histograms? Sparse-бакеты с автоматическим bucketing, экономия места в TSDB (Prometheus 2.40+).
-
Как Prometheus обрабатывает counter reset?
rate()/increase()детектируют падение значения и считают, что был reset, обновляют расчёт. Не используйтеdelta()на counters. -
Чем VictoriaMetrics лучше Prometheus? Лучшая компрессия, vmagent для агрегации/relabel, кластерный mode, не использует mmap → меньше OOM. Совместима с Prometheus exposition.
-
Что такое scrape interval и почему нельзя ставить 1s? Период между scrapes (default 15s). Меньший интервал = больше data points = TSDB взлетает по объёму.
-
Зачем разделять
/metricsна отдельный порт? Безопасность (не выставлять метрики наружу), не путать с бизнес-трафиком, отдельный rate limit. -
Что такое
upметрика? Автоматическая метрика Prometheus: 1 если последний scrape ОК, 0 если нет. Базис для алерта “сервис мёртв”. -
Как тестировать метрики? Создать отдельный
prometheus.NewRegistry(), проверять черезtestutil.GatherAndCompare. -
Что такое exemplars? Точечные ссылки в метрике на trace_id — позволяют из Grafana прыгнуть в Tempo на конкретный медленный запрос.
-
Как сделать service discovery в K8s? Prometheus Operator +
PodMonitor/ServiceMonitorCRDs, или нативныйkubernetes_sd_configs. -
Что такое Alertmanager? Сервер для маршрутизации, dedup, grouping и отправки алертов в Slack/PagerDuty/etc.
-
Сколько метрик можно отправлять с одного инстанса? Безопасно — до 100К time series. Свыше — нужны recording rules, агрегация, VictoriaMetrics.
6. Practice
Заголовок раздела «6. Practice»Упражнение 1: Базовый экспортёр
Заголовок раздела «Упражнение 1: Базовый экспортёр»Напишите HTTP-сервер на :8080 (бизнес /api/hello) и :9090 (/metrics). Экспортируйте Counter app_hello_total, инкрементируйте при каждом GET /api/hello.
Упражнение 2: Middleware с RED
Заголовок раздела «Упражнение 2: Middleware с RED»Реализуйте RED middleware с Counter http_requests_total{method,route,status} и Histogram http_request_duration_seconds. Замерьте через wrk/hey.
Упражнение 3: Cardinality protection
Заголовок раздела «Упражнение 3: Cardinality protection»Сделайте функцию normalizeRoute(path string) string, которая /users/123 → /users/:id. Подключите в middleware.
Упражнение 4: Custom collector
Заголовок раздела «Упражнение 4: Custom collector»Создайте WorkerPoolCollector, который при каждом scrape отдаёт pool_active (Gauge), pool_idle (Gauge), pool_queued (Gauge).
Упражнение 5: gRPC метрики
Заголовок раздела «Упражнение 5: gRPC метрики»Подключите go-grpc-middleware/v2/interceptors/prometheus к gRPC-серверу. Сделайте dashboard в Grafana с RED для метода GetUser.
Упражнение 6: Histogram buckets
Заголовок раздела «Упражнение 6: Histogram buckets»Для метрики db_query_duration_seconds подберите экспоненциальные бакеты от 0.5ms до 30s. Объясните выбор.
Упражнение 7: PromQL
Заголовок раздела «Упражнение 7: PromQL»Напишите PromQL-выражения:
- p99 latency за 5 минут.
- Error rate (5xx / total) в %.
- Скорость роста ошибок per route.
- Saturation пула (
pool_used / pool_size).
Упражнение 8: Alert
Заголовок раздела «Упражнение 8: Alert»Создайте alerting rule в alerts.yaml: алертим если p99 latency > 500ms за 10 минут с severity warning.
7. Источники
Заголовок раздела «7. Источники»- Официальная документация client_golang — https://pkg.go.dev/github.com/prometheus/client_golang.
- Prometheus docs: Best Practices — https://prometheus.io/docs/practices/.
- Prometheus: Histograms and Summaries — https://prometheus.io/docs/practices/histograms/.
- Brian Brazil, “Prometheus: Up & Running” (O’Reilly, 2nd edition, 2023).
- Google SRE Book: Monitoring — https://sre.google/sre-book/monitoring-distributed-systems/.
- Brendan Gregg: USE Method — https://www.brendangregg.com/usemethod.html.
- Tom Wilkie: RED Method — https://www.weave.works/blog/the-red-method-key-metrics-for-microservices-architecture/.
- VictoriaMetrics blog — https://victoriametrics.com/blog/.
- Native histograms KubeCon talk — поиск на YouTube за 2024-2026.
- Prometheus Operator — https://prometheus-operator.dev/.