> Какую метрику Prometheus использовать для подсчета RPS сервера (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Aston

Стек: Go

> Пример ответа

Короткий ответ

Для подсчёта RPS используйте Prometheus counter с лейблами под конкретный срез трафика, например http_requests_total. RPS вычисляется через rate-функцию: rate(http_requests_total[5m]) или sum(rate(...)) для агрегации. Counter обязателен, так как он монотонно возрастает и корректно обрабатывает рестарты. Gauge для этой задачи не подходит - он показывает мгновенное значение, а не скорость.

Подробное объяснение

RPS (requests per second) - это производная метрика, которая вычисляется из накопленного счётчика запросов. Prometheus предоставляет для этого функцию rate(), которая считает среднюю скорость изменения counter за окно времени.

Ключевые моменты:

  • Counter - единственный подходящий тип метрики. Он монотонно возрастает и сбрасывается только при рестарте процесса, что rate() корректно обрабатывает (учитывает reset).
  • Gauge не подходит, так как показывает текущее значение, а не скорость. Если вы будете хранить "количество запросов за последнюю секунду" в gauge, вы потеряете возможность пересчитать историю и получите шумные данные.
  • Histogram можно использовать, если нужен RPS в разрезе latency buckets, но для чистого RPS это избыточно.

Формула для вычисления:

rate(http_requests_total[5m])

Окно [5m] - это trade-off между гладкостью и отзывчивостью. Чем больше окно, тем стабильнее график, но медленнее реакция на всплески. Для алертинга обычно берут 1-5 минут.

Агрегация по всем инстансам:

sum(rate(http_requests_total[5m]))

Если нужно разбить по кодам ответа или эндпоинтам - добавляйте лейблы в counter и группируйте через by.

На практике

В Go-сервере метрику обычно регистрируют в middleware. Стандартный подход - использовать prometheus/client_golang:

  • Создайте counter с лейблами method, path, status.
  • Инкрементируйте его после обработки каждого запроса.
  • Для path используйте шаблон роута, а не фактический путь, иначе кардинальность метрики взорвётся.

На практике RPS редко смотрят в моменте - чаще строят дашборды с rate[5m] и алерты на падение или резкий рост. Также полезно считать RPS отдельно для успешных и ошибочных запросов, чтобы отличать деградацию от всплеска трафика.

Пример кода

GO
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
httpRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
)
func init() {
prometheus.MustRegister(httpRequests)
}
func metricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Используйте шаблон роута, не r.URL.Path
path := r.URL.Path
if route := r.Context().Value("route"); route != nil {
path = route.(string)
}
next.ServeHTTP(w, r)
// status code нужно перехватить через wrapper
httpRequests.WithLabelValues(r.Method, path, "200").Inc()
})
}
func main() {
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}

Как отвечать на собеседовании

Начните с прямого ответа: counter + rate(). Затем поясните, почему именно counter, а не gauge - это главный момент, который проверяют. Упомяните окно агрегации и trade-off между гладкостью и отзывчивостью. Если спросят про алерты - скажите, что для алертинга используют rate[1m] или rate[5m] в зависимости от критичности. Покажите, что понимаете проблему кардинальности лейблов - это отличает senior от junior.

Что проверяет интервьюер

  • Понимание типов метрик Prometheus и их назначения.
  • Умение вычислять производные метрики через rate().
  • Осознание trade-off при выборе окна агрегации.
  • Знание практических проблем: кардинальность лейблов, обработка рестартов, агрегация по инстансам.
  • Способность объяснить, почему gauge здесь не подходит.

Типичные ошибки

  • Предложение использовать gauge для хранения "текущего RPS" - это антипаттерн, ломающий историческую перспективу.
  • Использование фактического пути в лейбле path без шаблонизации - приводит к взрыву кардинальности.
  • Игнорирование обработки рестартов - кандидат не знает, что rate() учитывает reset counter.
  • Выбор слишком маленького окна (например, [10s]) для алертинга - даёт ложные срабатывания.
  • Путаница между rate() и irate() - последний показывает мгновенную скорость и слишком шумный для RPS.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью