Профилирование, trace и fuzz в Go
Go поставляет профилирование и трассировку в toolchain — отдельный APM для первичной диагностики не обязателен. Статья развивает тестирование и механику языка.
См. также: Асинхронность и горутины · Рекомендации по разработке · Сборка мусора.
Порядок работы с производительностью
- Корректность — тесты,
-race. - Benchmark —
go test -bench, сравнение до/после. - Профиль — CPU, heap, goroutine через
pprof. - Trace — задержки, блокировки, планировщик.
- Оптимизация — точечно, с повторным benchmark.
Сначала измерение, потом правка. Переписывание main() для тестируемости делает benchmark и pprof осмысленными.
Benchmark
func BenchmarkParseLines(b *testing.B) {
data := []byte("line1\nline2\nline3\n")
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = parseLines(data)
}
}
go test -bench=BenchmarkParseLines -benchmem ./...
Разбор:
b.Nподбирает runtime; внутри цикла — только измеряемый код.-benchmemпоказывает аллокации на операцию — частый источник регрессий.ReportAllocs()добавляет статистику alloc/op в вывод.
benchstat
Установка: go install golang.org/x/perf/cmd/benchstat@latest.
go test -bench=. -count=10 ./pkg/... > old.txt
# ... правки ...
go test -bench=. -count=10 ./pkg/... > new.txt
benchstat old.txt new.txt
Разбор:
-count=10сглаживает шум OS и CPU frequency scaling.benchstatсчитает p-value и выводит «+5.2%» только если разница статистически заметна.- Без benchstat легко принять случайный выигрыш за оптимизацию.
CPU-профиль (pprof)
Из теста
go test -cpuprofile=cpu.prof -bench=BenchmarkParseLines ./...
go tool pprof cpu.prof
В интерактивном режиме: top, list parseLines, web (нужен graphviz).
HTTP-сервис
import _ "net/http/pprof"
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// ... ваш сервер ...
}
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Разбор:
- Blank import регистрирует
/debug/pprof/*на DefaultServeMux. profile?seconds=30собирает CPU-sample во время реальной нагрузки.- В production endpoint изолируют firewall или отдельный admin-порт — см. 30.md.
Heap и goroutine
| Профиль | URL / флаг | Вопрос |
|---|---|---|
| Heap | /debug/pprof/heap | Кто аллоцирует память |
| Goroutine | /debug/pprof/goroutine | Утечки горутин |
| Block | /debug/pprof/block | Блокировки на mutex/channel |
| Mutex | /debug/pprof/mutex | Контention мьютексов |
go tool pprof http://localhost:6060/debug/pprof/heap
Разбор:
- Heap показывает in-use и allocations; для утечек смотрят рост между двумя снимками.
- Goroutine profile полезен, когда счётчик горутин растёт без остановки — часто забытый
goбез exit.
go tool trace
go test -trace=trace.out -bench=BenchmarkParseLines ./...
go tool trace trace.out
Для HTTP-сервера — runtime/trace или net/http/pprof endpoint /debug/pprof/trace.
Разбор:
- Trace показывает timeline горутин, GC, syscall, блокировки — то, что не видно в aggregate CPU profile.
- Полезен, когда latency высокая, а CPU profile пустой (ожидание I/O).
Fuzzing (Go 1.18+)
Fuzz-тест генерирует входные данные и ищет падения и несоответствия:
func FuzzParseAge(f *testing.F) {
f.Add("21")
f.Add("0")
f.Fuzz(func(t *testing.T, s string) {
age, err := parseAge(s)
if err != nil {
return
}
if age < 0 || age > 150 {
t.Fatalf("age out of range: %d", age)
}
})
}
go test -fuzz=FuzzParseAge -fuzztime=30s ./...
Разбор:
f.Add— seed-кorpus; fuzzer мутирует строки и сохраняет crashing input вtestdata/fuzz/.- Fuzz дополняет table-driven тесты на неожиданных входах (Unicode, длинные строки).
- Не заменяет
-raceи не доказывает корректность — только находит краевые сбои.
go:generate и примеры
Директива go:generate:
//go:generate stringer -type=Status
type Status int
go generate ./...
Example-функции (документация + тест) — см. 192.md; testing/quick — случайные значения для property-подобных проверок без полноценного fuzz.
Кросс-компиляция
GOOS=linux GOARCH=amd64 go build -o app ./cmd/app
Разбор:
- Go кросс-компилирует из коробки; CGO усложняет (нужен cross-C-compiler).
- В CI matrix собирают бинарники под несколько платформ; benchmark гоняют на одной эталонной машине.
Недостижимый код
go test -coverprofile=cover.out ./...
go tool cover -func=cover.out
Пакет golang.org/x/tools/go/analysis/passes/unreachable и staticcheck находят мёртвые ветки. Удаление unreachable-кода упрощает профили — меньше шума в list.
Ключевые тезисы
- Benchmark + benchstat — доказательство, что оптимизация реальна.
- pprof отвечает на «где CPU/память»; trace — на «кто ждал и почему».
- Fuzz ловит краевые входы;
-race— гонки данных. - Профилируйте под реалистичной нагрузкой, не на пустом сервере.
Мини-практикум
- Добавьте
-benchmemк существующему benchmark в проекте. - Снимите CPU profile при нагрузке на Gin-сервис; найдите top-3 функции.
- Напишите
Fuzz*для парсера, который принимает строку с числом.
Типичные ошибки
| Ошибка | Последствие |
|---|---|
Benchmark с time.Sleep внутри | Замеряется sleep, а не код |
Один прогон -bench | Случайные выводы |
| pprof на dev без нагрузки | Пустой или misleading profile |
Fuzz без seed f.Add | Дольше сходится к интересным кейсам |
Связанные материалы
- Тестирование в Go — unit, httptest, CI
- Механика языка и гонки данных —
-race, pprof endpoint - Особенности языка Go — GC и аллокации
- Следующий шаг — CLI на cobra и viper
Базовый разбор HTTP — HTTP как основа веб-интеграций.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Основы языка Go - философия простоты, модель компиляции и идиоматичный подход к системной разработке. Go — это статически типизированный язык программирования общего назначения, разработанный компанией Google для создания эффективных, масштабируемых и надежных систем. Набор советов, правил, принципов и обычаев в разработке на этом языке. История Go - инженерные цели языка, философия простоты и эволюция инструментов экосистемы. Экосистема приложений на Go - встроенные инструменты, workflow разработки и практики сопровождения проектов. Кавычки, rune и string, точка, запятая, автоматическая вставка точки с запятой, скобки, подчёркивания и типичные ошибки новичков в Go. Предопределённые идентификаторы не являются ключевыми словами, но имеют специальное значение в языке. Их можно переопределить в локальной области видимости, но делать это не рекомендуется. Набор функций, которые включены в стандартную библиотеку языка. Особенности Go - интерфейсы, композиция, модель ошибок и практики написания поддерживаемого кода. Go вводит конкурентность через встроенные синтаксические конструкции и правила выполнения. Ниже рассматриваются основные направления практического применения Go, объяснённые через призму его технических характеристик и требований реальных инфраструктур. Типизация, набор правил определения типа данных значений языка.Основы языка Go
Что требуется знать перед началом изучения языка программирования Go
Рекомендации по разработке на Go
История языка Go
Экосистема приложений на Go
Синтаксис и пунктуация в Go
Ключевые слова языка Go
Встроенные функции и пакеты Go
Особенности языка Go
Синтаксические конструкции Go
Области применения Go
Типы данных и объявление переменных в Go