TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7119 4.08K
📊 heap-профилирование без единой строки кода

Coroot выпустили zero-config heap-профилирование для Go. Агент читает профили прямо из памяти работающего процесса через /proc/<pid>/mem, не трогая сам процесс и не требуя от него ничего.

Раньше, чтобы получить heap-профиль Go-сервиса, нужно было подключить net/http/pprof, поднять эндпоинт, настроить скрейпинг. Если сервис чужой или деплой нежелателен, то вы просто не получали данных. Coroot решил эту проблему на уровне ноды.

Механика такая: Go-рантайм уже собирает heap-профили внутри себя через runtime.MemProfile(). Данные живут в глобальной переменной runtime.mbuckets. Coroot находит адрес этой переменной в символьной таблице бинаря, читает связный список бакетов и конвертирует всё в pprof-формат.

Два нетривиальных момента, которые пришлось решить:

Stripped-бинари. Бинарь собран с -ldflags="-s" и символьная таблица отсутствует и найти mbuckets невозможно. Такие процессы пропускаются.

Линкер отключает профилирование. Если в бинаре нет импорта runtime/pprof или net/http/pprof, линкер выставляет флаг disableMemoryProfiling и рантайм устанавливает MemProfileRate = 0. Profiling не работает вообще. Coroot умеет это обнаружить и записать дефолтное значение обратно через тот же /proc/<pid>/mem:

--go-heap-profiler=disabled  # выключено
--go-heap-profiler=enabled # по умолчанию, только пассивное чтение
--go-heap-profiler=force # записывает MemProfileRate если он равен нулю


Как это выглядит в деле

Команда показала два демо-сценария на сервисе product-catalog.

Первый: включили GC-давление. Каждый запрос прогонял маршаллинг/анмаршаллинг данных десятки раз и строил ненужные структуры суммарно на ~2 МБ. Латентность api-gateway выросла с 0.16s до 3.76s. CPU-профиль показал gcBgMarkWorker — GC грузит CPU, но не понятно откуда. Heap-профиль сразу указал на main.inefficientEnrichProducts с JSON-энкодерами и аллокациями в цикле.

Второй: включили утечку памяти. Каждый запрос добавлял данные в глобальный срез без удаления. Память росла быстро. RCA-движок Coroot сравнил heap-профиль во время инцидента с профилем до него и выдал дифф: main.appendToProductCache отвечает за 99.6% новых аллокаций. Не «что-то растёт», а конкретная функция.

Что добавилось в метрики

Поскольку агент уже считает дельты аллокаций по бакетам, два новых счётчика появились бесплатно:
container_go_alloc_bytes_total    # байты аллоцированные за период
container_go_alloc_objects_total # объекты аллоцированные за период


Heap-профилирование теперь работает для любого Go-процесса на ноде без изменений в коде, без pprof-эндпоинтов, без рестарта. Особенно полезно SRE-командам, которые обслуживают сервисы, написанные другими.

➡️ Источник

Кроме профилирования без единой строчки, можно сделать себе агента, который будет писать остальные строчки кода. Свободные места можно посчитать на пальцах одной руки 👉 Регистрация здесь

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoToProduction
  • 🔥 9
  • ❤ 3
  • 👍 2
  • 👏 1
  • 🥱 1
More from @goproglib
  1. Sep 30, 2026🧑‍💻 Эмулятор AWS-сервисов Kumo — это небольшой инструмент на Go для локальной имитации A…
  2. Sep 29, 2026👨‍💻 Библиотека для написания LSP-серверов Написать свой Language Server с нуля на Go сло…
  3. Sep 28, 2026🤔 Вопрос с собеседования по Go Что выведет программа? ❤️ — 1 true / 0 false 🔥 — 1 true /…
  4. Sep 28, 2026👩‍💻 Что на самом деле происходит внутри Go map? После Go 1.24 обычный map внутри работае…
  5. Sep 26, 2026🔥 В Go 1.27 появился portable SIMD До этого SIMD-оптимизации в Go требовали архитектурног…
  6. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →