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