Пост канала «Библиотека Go (Golang) разработчика» от 28.06.2026
Сервис на проде внезапно упирается в полку по процессору.
Что делает новичок? Сидит и смотрит в исходники взглядом гипнотизера, пытаясь угадать: "Ну, наверное, это регулярка тормозит". Или обкладывает весь код вызовами time.Now() в начале и time.Since() в конце каждой функции.
Сеньор открывает терминал, пишет одну команду и через 30 секунд получает точное имя функции, номер строки и процент украденного CPU. Наш инструмент pprof.
Он встроен прямо в стандартную библиотеку Go. Работает по принципу семплирования: раз в 10 миллисекунд рантайм Go "замирает", смотрит на стеки всех запущенных горутин и записывает: "Так, в эту микросекунду процессор выполнял функцию json.Unmarshal.
Давайте проведем вскрытие за 4 шага.
Шаг 1. Включаем «жучка» в коде
Всё, что нужно сделать в вашем сервисе - импортировать один пакет со знаком подчеркивания:
package main
import (
"net/http"
_ "net/http/pprof" // <-- Подключаем магию
)
func main() {
// ... ваша основная бизнес-логика ...
// Вешаем pprof на отдельный внутренний порт!
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
}
Нюанс для Senior-ов: Магия _ "net/http/pprof" работает только с дефолтным http.DefaultServeMux. Если вы используете chi, gin или кастомный http.NewServeMux(), роуты профилировщика нужно регистрировать в ваш роутер руками (они лежат в пакете net/http/pprof как обычные хендлеры).
Шаг 2. Натравливаем профилировщик
Сервис крутится под нагрузкой. Открываем терминал на своей рабочей машине и говорим Go: *"Послушай этот сервер 30 секунд и собери мне статистику"*:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Терминал подумает полминуты и превратится в интерактивную консоль (pprof).
Шаг 3. Магия двух колонок
Внутри консоли пишем команду top10:
Showing nodes accounting for 2.45s, 88.1% of 2.78s total
flat flat% sum% cum cum%
1.82s 65.5% 65.5% 1.82s 65.5% regexp.(*bitState).reset
0.34s 12.2% 77.7% 0.45s 16.2% encoding/json.Unmarshal
0.15s 5.4% 83.1% 2.50s 89.9% main.processOrder
Главная ловушка новичка - смотреть на колонку cum.
• flat - сколько времени процессор провел исключительно внутри тела этой функции.
• cum (cumulative) - сколько времени процессор провел в этой функции + во всех функциях, которые она вызвала внутри себя.
Пример: У функции main.processOrder показатель cum равен 89.9%, но flat всего 5.4%. Это значит, что сама она почти ничего не считает, она просто вызвала тяжелую регулярку (regexp.reset, у которой flat аж 65.5%). Лечить нужно регулярку, а не processOrder!
Шаг 4. Визуальный экстаз (Flame Graph)
Смотреть в ASCII-таблицы в 2026 году больно. Выходим из консоли (Ctrl+D) и запускаем ту же команду, но добавив флаг -http:
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30
В браузере мгновенно откроется шикарный веб-интерфейс. Переключаем вид сверху в режим Flame Graph (Огненный граф):
1. Перед вами "столбы". Чем шире столб по горизонтали - тем больше CPU сожрала эта функция. 2. Кликаем мышкой на самый широкий красный столб.
2. Переключаемся во вкладку Source.
3. Видим наш исходный код, где подсвечена конкретная строчка var re = regexp.MustCompile(...), компилирующая регулярку внутри цикла в хендлере. Прод спасен.
🔥 Senior Warning: Кровавая цена дефолта
Никогда не выставляйте порт 6060 наружу в интернет!
По адресу /debug/pprof/goroutine?debug=2 любой школьник без авторизации скачает полный текстовый дамп всех запущенных горутин. В их стеках будут лежать ваши пароли от БД в сыром виде, Bearer-токены пользователей и приватные ключи.
В продакшене pprof обязан висеть строго на localhost, куда разработчик заходит через kubectl port-forward или SSH-туннель.
👉 @golang_lib