Как вы находите и анализируете узкие места (bottlenecks) в Go-приложении?

Ответ

Для поиска узких мест в Go-проекте я использую комплексный подход, сочетая статический анализ и динамическое профилирование.

Основной принцип: Сначала измеряй, потом оптимизируй.

1. Профилирование с помощью pprof

Это главный инструмент для анализа производительности работающего приложения. Я подключаю net/http/pprof и анализирую различные профили:

import _ "net/http/pprof"

go func() {
    // pprof будет доступен по адресу http://localhost:6060/debug/pprof/
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()
  • CPU Profile: go tool pprof http://.../profile?seconds=30 — показывает, какие функции потребляют больше всего процессорного времени.
  • Heap Profile: go tool pprof http://.../heap — анализирует распределение памяти в куче, помогает найти утечки или неэффективное использование памяти.
  • Goroutine Profile: go tool pprof http://.../goroutine — показывает стектрейсы всех текущих горутин, полезно для отладки утечек горутин.
  • Block Profile: Показывает, где горутины блокируются в ожидании синхронизации (каналы, мьютексы). Включается через runtime.SetBlockProfileRate().

2. Бенчмарки

Для анализа производительности конкретных функций я пишу бенчмарки с помощью встроенного пакета testing.

func BenchmarkMyFunction(b *testing.B) {
    for i := 0; i < b.N; i++ {
        // Код, производительность которого измеряется
    }
}

Запуск с флагом -benchmem показывает не только время выполнения, но и количество аллокаций памяти на операцию.
go test -bench=. -benchmem

3. Трассировка

Инструмент go tool trace позволяет получить детальную картину выполнения программы: работа планировщика, переключения контекста горутин, события сборки мусора. Это помогает находить проблемы с конкурентностью и задержками.

4. Мониторинг в реальном времени

В продакшн-среде я полагаюсь на системы мониторинга:

  • Prometheus с кастомными метриками (время ответа, количество ошибок, длина очередей).
  • Expvar для экспорта внутренних переменных состояния приложения (например, счетчиков).

5. Анализ логов

Анализ логов, особенно с замером времени выполнения запросов или операций, часто помогает выявить аномально медленные участки кода.