Мониторинг Go приложений: метрики и алерты

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему мониторинг критичен для Go-приложений

Go (Golang) завоевал популярность в разработке высоконагруженных микросервисов, API-шлюзов и сетевых утилит благодаря своей производительности и простоте. Однако даже самое стабильное приложение может столкнуться с утечками памяти, зависаниями горутин или внезапным ростом задержек. Именно здесь на помощь приходит мониторинг — ключевая практика Site Reliability Engineering (SRE).

В этой статье мы разберем, как настроить мониторинг Go-приложений с помощью стека Prometheus + Grafana, какие метрики собирать в первую очередь и как настроить алерты для предотвращения инцидентов. Материал будет полезен как начинающим Go-разработчикам, так и опытным инженерам, желающим улучшить observability своих сервисов.

1. Основные метрики Go-приложения

Прежде чем настраивать мониторинг, важно понять, какие метрики являются жизненно важными для Go-сервиса. Их можно разделить на три категории:

1.1. Метрики рантайма Go

Go runtime предоставляет богатую информацию о состоянии приложения. С помощью пакета runtime и стандартного экспортера expvar можно получать данные о:

  • Количество горутин (runtime.NumGoroutine()) — резкий рост указывает на утечку горутин.
  • Использование памяти (runtime.ReadMemStats()) — отслеживайте Alloc, HeapInuse и GCStats.
  • Время сборки мусора — если GC занимает более 5% времени, это сигнал к оптимизации.
  • Количество системных вызовов — может указывать на блокировки.

1.2. Бизнес-метрики

Для понимания здоровья сервиса необходимо мониторить бизнес-показатели:

  • RPS (Requests Per Second) — количество запросов в секунду.
  • Latency (P50, P95, P99) — задержки обработки запросов.
  • Error rate — процент ошибок (5xx, 4xx).
  • Количество активных соединений (база данных, внешние API).

1.3. Метрики инфраструктуры

Не забывайте про системные метрики: CPU, память, I/O диска, сетевые пакеты. Они помогают отличить проблему приложения от проблем хоста.

2. Интеграция с Prometheus: экспорт метрик

Prometheus — стандарт де-факто для сбора метрик в мире Go. Рассмотрим пошаговую интеграцию.

2.1. Установка клиента Prometheus для Go

Добавьте зависимость в ваш go.mod:

go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promhttp

2.2. Создание кастомных метрик

Пример создания счетчика запросов и гистограммы для времени ответа:

package main

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

var (
    requestCount = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "endpoint", "status"},
    )
    requestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "Duration of HTTP requests in seconds",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "endpoint"},
    )
)

func init() {
    prometheus.MustRegister(requestCount)
    prometheus.MustRegister(requestDuration)
}

func metricsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
        next.ServeHTTP(wrapped, r)
        duration := time.Since(start).Seconds()

        requestCount.With(prometheus.Labels{
            "method":   r.Method,
            "endpoint": r.URL.Path,
            "status":   http.StatusText(wrapped.statusCode),
        }).Inc()

        requestDuration.With(prometheus.Labels{
            "method":   r.Method,
            "endpoint": r.URL.Path,
        }).Observe(duration)
    })
}

type responseWriter struct {
    http.ResponseWriter
    statusCode int
}

func (rw *responseWriter) WriteHeader(code int) {
    rw.statusCode = code
    rw.ResponseWriter.WriteHeader(code)
}

func main() {
    mux := http.NewServeMux()
    mux.Handle("/metrics", promhttp.Handler())
    mux.Handle("/api/hello", metricsMiddleware(http.HandlerFunc(helloHandler)))

    http.ListenAndServe(":8080", mux)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, World!"))
}

2.3. Автоматические метрики Go runtime

Prometheus клиент автоматически регистрирует метрики Go runtime (память, горутины, GC). Они доступны по эндпоинту /metrics после импорта:

import _ "github.com/prometheus/client_golang/prometheus/collectors"

Это добавит метрики с префиксом go_ — go_goroutines, go_memstats_alloc_bytes и другие.

3. Настройка алертов в Prometheus и Alertmanager

Сбор метрик бесполезен без своевременного оповещения. Настроим алерты для критических ситуаций.

3.1. Правила алертов (Prometheus Rules)

Создайте файл alerts.yml:

groups:
  - name: go_app_alerts
    rules:
      - alert: HighGoroutineCount
        expr: go_goroutines > 1000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High goroutine count in {{ $labels.instance }}"
          description: "Goroutine count is {{ $value }} (threshold: 1000)"

      - alert: HighMemoryUsage
        expr: go_memstats_alloc_bytes / 1024 / 1024 > 500
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Memory usage exceeded 500MB in {{ $labels.instance }}"
          description: "Current memory: {{ $value }} MB"

      - alert                

Блоги

Рекомендаций по книгам