Введение: почему мониторинг критичен для 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