GoMiddleTechnical
Как использовать pprof и runtime/trace для диагностики CPU, memory и goroutine leaks?
pprof собирает CPU/memory/goroutine профили через HTTP-endpoint или benchmarks; runtime/trace даёт timeline с goroutine scheduling. Анализируют через go tool pprof и go tool trace.
pprof: подключение и сбор профилей
Добавьте один импорт — и HTTP-endpoint появится автоматически:
import (
"net/http"
_ "net/http/pprof" // регистрирует /debug/pprof/*
)
func main() {
go http.ListenAndServe("localhost:6060", nil)
// ... основной сервер
}
Доступные endpoints:
/debug/pprof/profile?seconds=30— CPU профиль на 30 секунд/debug/pprof/heap— heap allocations/debug/pprof/goroutine?debug=2— goroutine dump с полными стеками/debug/pprof/allocs— все аллокации (включая короткоживущие)/debug/pprof/mutex— contention на мьютексах/debug/pprof/block— блокировки на channel/sync примитивах
Сбор и анализ CPU профиля
# Собрать 30-секундный CPU профиль
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Интерактивный режим:
(pprof) top10 # топ-10 функций по CPU
(pprof) list MyFunc # аннотированный исходник
(pprof) web # открыть flame graph в браузере (нужен graphviz)
# Сохранить и открыть позже:
curl -o cpu.pprof http://localhost:6060/debug/pprof/profile?seconds=30
go tool pprof -http=:8080 cpu.pprof
Heap профиль: диагностика утечек памяти
go tool pprof http://localhost:6060/debug/pprof/heap
(pprof) top10 # топ по inuse_space
(pprof) -inuse_objects # по количеству объектов
(pprof) -alloc_space # по общему объёму аллокаций за всё время
Сравнение двух снапшотов для поиска утечки:
curl -o before.pprof http://localhost:6060/debug/pprof/heap
# подождать, нагрузить сервис
curl -o after.pprof http://localhost:6060/debug/pprof/heap
go tool pprof -base before.pprof after.pprof
(pprof) top10
Goroutine leak через pprof
curl http://localhost:6060/debug/pprof/goroutine?debug=2 | grep -A 5 "goroutine"
# Ищем сотни/тысячи goroutine с одинаковым стеком
runtime/trace: детальный timeline
import (
"os"
"runtime/trace"
)
func main() {
f, _ := os.Create("trace.out")
defer f.Close()
trace.Start(f)
defer trace.Stop()
// ... ваш код
}
go tool trace trace.out
# Открывает веб-интерфейс: goroutine scheduling, GC pauses, syscall latency
Trace показывает:
- Когда goroutine была preempted или заблокирована
- GC паузы и их длительность
- Latency network/syscall по каждой goroutine
- Heap size timeline
pprof в бенчмарках (без запущенного сервера)
go test -bench=BenchmarkMyFunc -cpuprofile=cpu.pprof -memprofile=mem.pprof ./...
go tool pprof -http=:8080 cpu.pprof
Включение mutex и block профилей
import "runtime"
func init() {
runtime.SetMutexProfileFraction(1) // 1 = каждый lock
runtime.SetBlockProfileRate(1) // 1 = каждая блокировка
}
Подводные камни
- pprof endpoint в production без auth:
/debug/pprofоткрывает внутреннее состояние; закройте firewall-ом или basic auth. - SetMutexProfileFraction(1) в prod: профилирование каждого lock добавляет ~10% overhead; используйте fraction 100 или только при расследовании.
- Heap профиль vs allocs:
/heapпоказывает живые объекты,/allocs— все когда-либо созданные; для поиска утечки нуженheap. - runtime/trace с большой нагрузкой: файл trace растёт очень быстро; собирайте не более 5–10 секунд.
- Flame graph требует graphviz:
go tool pprof -webпадает безdot; используйте-http=:8080как альтернативу. - CPU профиль с sampling: pprof семплирует каждые 10ms; короткие функции могут не попасть в профиль — используйте бенчмарки с
-cpuprofile. - Интерпретация cumulative vs flat:
flat— время в самой функции,cum— включая вызываемые; оптимизируйте функцию с высокимflat.
Common mistakes
- Отвечать определением без production-сценария.
- Не называть runtime boundary, security boundary или failure mode.
- Игнорировать версию API, observability и тестовую проверку.
What the interviewer is testing
- Объясняет механизм своими словами и без выдуманных API.
- Называет реальные риски, диагностику и критерий корректности.
- Связывает ответ с текущей документацией и миграционными ограничениями.