Go имеет мощный встроенный профайлер (pprof), который позволяет анализировать различные аспекты работы программы. Вот как его правильно интегрировать в приложение.
Стандартный пакет net/http/pprof
автоматически регистрирует обработчики для профилирования на существующем HTTP-роутере.
import _ "net/http/pprof"
Этот импорт регистрирует следующие эндпоинты:
/debug/pprof/
- общая информация/debug/pprof/heap
- профиль памяти/debug/pprof/profile
- CPU профиль/debug/pprof/goroutine
- стек горутин/debug/pprof/block
- блокировки/debug/pprof/mutex
- мьютексы/debug/pprof/trace
- трассировка выполненияpackage main
import (
"log"
"net/http"
_ "net/http/pprof" // автоматически добавляет обработчики pprof
"time"
)
func busyWork() {
for {
time.Sleep(1 * time.Millisecond)
}
}
func main() {
// Запускаем горутину с нагрузкой
go busyWork()
// Запускаем HTTP сервер для профилирования
log.Println(http.ListenAndServe("localhost:6060", nil))
}
После запуска откройте в браузере http://localhost:6060/debug/pprof/
Для точечного профилирования можно использовать API pprof напрямую:
import (
"os"
"runtime/pprof"
)
func startCPUProfile() {
f, err := os.Create("cpu.prof")
if err != nil {
log.Fatal(err)
}
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal(err)
}
// Вызовите pprof.StopCPUProfile() перед выходом
}
func writeHeapProfile() {
f, err := os.Create("heap.prof")
if err != nil {
log.Fatal(err)
}
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal(err)
}
f.Close()
}
Собранные профили можно анализировать с помощью go tool pprof:
# CPU профиль
go tool pprof cpu.prof
# Память (из HTTP)
go tool pprof http://localhost:6060/debug/pprof/heap
# Интерактивный CPU профиль 30 секунд
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
В интерактивном режиме доступны команды:
top
- топ функций по использованию ресурсовlist FunctionName
- детализация по конкретной функцииweb
- визуализация графа вызовов (требуется Graphviz)import "runtime/pprof"
func saveGoroutineProfile() {
f, err := os.Create("goroutines.pprof")
if err != nil {
log.Fatal(err)
}
if err := pprof.Lookup("goroutine").WriteTo(f, 0); err != nil {
log.Fatal(err)
}
f.Close()
}
import "runtime"
func enableBlockProfile() {
runtime.SetBlockProfileRate(1) // Записывать каждую блокировку
}
import (
"os"
"runtime/trace"
)
func startTrace() {
f, err := os.Create("trace.out")
if err != nil {
log.Fatal(err)
}
if err := trace.Start(f); err != nil {
log.Fatal(err)
}
// Вызовите trace.Stop() перед выходом
}
Анализ трассировки:
go tool trace trace.out
Для популярных веб-фреймворков нужно явно подключить роуты:
import (
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
pprof.Register(router) // добавляет /debug/pprof/* роуты
router.Run(":8080")
}
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"net/http/pprof"
)
func main() {
e := echo.New()
// Добавляем pprof роуты
pprofGroup := e.Group("/debug/pprof")
pprofGroup.GET("", echo.WrapHandler(http.HandlerFunc(pprof.Index)))
pprofGroup.GET("/:profile", echo.WrapHandler(http.HandlerFunc(pprof.Index)))
// ... остальные обработчики
e.Start(":8080")
}
func pprofAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !isAuthorized(r) {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
h(w, r)
}
}
// Защищенные роуты
http.HandleFunc("/debug/pprof/", pprofAuth(pprof.Index))
Встроенный профайлер Go предоставляет мощные инструменты для анализа производительности. Для базового использования достаточно импортировать net/http/pprof
и запустить HTTP-сервер. Для продвинутых сценариев используйте прямое API pprof и runtime-пакеты. Всегда соблюдайте меры предосторожности при профилировании в production.