Мониторинг приложений Go (Golang): от метрик до профилирования
Go (Golang) — язык, созданный для высоконагруженных серверных приложений. Однако даже самый производительный код может давать сбои, утечки памяти или неоправданно высокую задержку. Без мониторинга вы рискуете узнать о проблеме только от разгневанных пользователей. В этой статье разберём ключевые библиотеки и инструменты для мониторинга Go-приложений: от сбора метрик до трейсинга и профилирования.
Зачем мониторить Go-приложение?
- Производительность: отслеживать время ответа, количество горутин, использование CPU и памяти.
- Надёжность: контролировать ошибки, паники, количество перезапусков.
- Масштабирование: понимать, когда нужно добавить реплики.
- Бизнес-метрики: количество запросов, активные пользователи, объём обработанных данных.
1. Встроенный пакет expvar
Самый простой способ — expvar. Он предоставляет HTTP-эндпоинт с базовыми метриками: количество горутин, использование памяти, время работы. Подходит для быстрого старта.
package main
import (
"expvar"
"net/http"
)
var requestCount = expvar.NewInt("requests_total")
func handler(w http.ResponseWriter, r *http.Request) {
requestCount.Add(1)
w.Write([]byte("Hello, Go!"))
}
func main() {
http.HandleFunc("/", handler)
// Метрики доступны по адресу /debug/vars
http.ListenAndServe(":8080", nil)
}
Запустите приложение и откройте http://localhost:8080/debug/vars — вы увидите JSON с метриками.
2. Prometheus + prometheus/client_golang
Prometheus — стандарт де-факто для сбора метрик в Go. Библиотека prometheus/client_golang позволяет регистрировать кастомные метрики: счётчики, гистограммы, суммарии.
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"},
)
)
func init() {
prometheus.MustRegister(httpRequests)
}
func handler(w http.ResponseWriter, r *http.Request) {
httpRequests.WithLabelValues(r.Method, r.URL.Path).Inc()
w.Write([]byte("OK"))
}
func main() {
http.HandleFunc("/", handler)
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}
Эндпоинт /metrics отдаёт данные в формате, который понимает Prometheus. Далее можно настроить дашборды в Grafana.
3. Профилирование с pprof
Пакет net/http/pprof добавляет эндпоинты для профилирования: CPU, память, блокировки, горутины. Это незаменимый инструмент для поиска узких мест.
package main
import (
"net/http"
_ "net/http/pprof" // подключаем профилировщик
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Профилирование активно"))
})
http.ListenAndServe(":6060", nil)
}
Теперь можно запустить:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Это соберёт 30-секундный профиль CPU. Анализируйте его в интерактивном режиме или экспортируйте в SVG/PDF.
4. OpenTelemetry — трейсинг и метрики
OpenTelemetry (OTel) — современный стандарт для наблюдаемости. Он объединяет метрики, логи и трейсы. Для Go есть официальный SDK go.opentelemetry.io/otel.
package main
import (
"context"
"log"
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
func initTracer() func() {
exporter, _ := stdouttrace.New(stdouttrace.WithPrettyPrint())
tp := trace.NewTracerProvider(
trace.WithBatcher(exporter),
)
otel.SetTracerProvider(tp)
return func() { tp.Shutdown(context.Background()) }
}
func handler(w http.ResponseWriter, r *http