awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

Как flame graph строится из сэмплов и как использовать его в production

Суть Одинаковые стеки схлопываются, алфавитная сортировка группирует родителей с детьми, а ширина — это число сэмплов. Зная алгоритм, никогда не перепутаешь x-ось с временем. Profiling интегрируется с SLO burn, deploy diff и capacity planning.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 15 min

Старший инженер на конференции спрашивает: «Какая функция выполняется раньше этой на flame graph?» Он указывает на два соседних фрейма на одном уровне. Ответ: ни один — x-ось алфавитная. Если этого не знать, потеряешь часы на неверную гипотезу.

Как flame graph строится из сэмплов

Каждый сэмпл — список имён функций от leaf (выполняется сейчас) до root (точка входа программы). После окна профилирования:

  1. Собираются все сэмплы.
  2. Одинаковые стеки схлопываются в одну колонку — их счётчики суммируются, делая колонку шире.
  3. Для рендеринга все уникальные стеки сортируются алфавитно по корневой функции — так один и тот же родитель группирует дочерние элементы рядом.
  4. Для каждого уровня прямоугольники рисуются с шириной, пропорциональной счётчику.

Читается сверху вниз: выбери leaf-фрейм (верх), проверь его ширину, спустись вниз, чтобы увидеть, кто его вызывает.

Самая дорогая ошибка прочтения

Позиция по x-оси — алфавитный порядок полного пути стека, не время, не порядок вызовов. Фрейм, стоящий левее другого на том же уровне, не говорит ничего о том, какой из них выполнился первым. Он говорит только о том, что путь его стека раньше по алфавиту.

Это самая распространённая ошибка инженеров при первом чтении flame graph. Если видишь два широких фрейма рядом и думаешь «сначала A, потом B», ты делаешь ложный вывод. Оба могут вызываться одним родителем в разные моменты, из несвязанных code path, из распараллеленного кода.

Если нужен порядок времени — правильный инструмент это trace view (timeline span’ов в стиле Gantt). Flame graph отвечает «что» горячее; traces отвечают «когда» в запросе выполнялся каждый шаг.

Рабочие процессы с профилями в production

SLO burn drilldown: Срабатывает SLO alert → кликаешь ссылку → временной диапазон предфильтрован по burn-окну → CPU + off-CPU flame graph рядом → определяешь изменившуюся функцию → привязываешь к деплою. Менее 90 секунд от пейджера до git blame для любого инцидента, где баг работал на CPU.

Обнаружение регрессий деплоя: Захватываешь профиль до и после деплоя под сравнимой нагрузкой. Делаешь diff: дифференциальный flame graph окрашивает фреймы по относительному изменению — красный для выросших фреймов, синий для сократившихся, белый для неизменных. Новые широкие красные фреймы, которых не было до деплоя — это регрессия. Production-grade continuous-profile бэкенды (Pyroscope, Datadog) включают это из коробки: «compare versions» выбирает два коммита или временных окна и рендерит diff.

Profile-as-data: запросы за пределами flame graph:

Профили — это временные ряды сэмплов стека; бэкенды всё чаще позволяют делать к ним запросы как к базе данных:

  • «Top-10 функций по self-CPU по всем сервисам за последний час» → capacity planning.
  • «Найти все профили, где функция X входит в top-5» → оценка влияния перед удалением медленной библиотеки.
  • «Сгруппировать flame graph’ы по Kubernetes-ноде» → найти горячие ноды.
  • «Alert при появлении новой функции в top-5 после деплоя» → автоматическое обнаружение регрессии.
Рабочий процессТриггерДействиеРезультат
SLO burn drillAlertФильтр профиля по burn-окнуГорячая функция за <90 с
Регрессия деплояДеплойDiff pre vs post профилейНовый горячий фрейм выделен красным
Capacity planningКвартальноTop-N функций по всему флотуКандидаты оптимизации в рейтинге
Trace-id drillМедленный span в traceФильтр профиля по trace-idFlame graph для этого запроса
Почему это работает

Почему дифференциальные профили находят то, что пропускают дашборды. Стандартный дашборд latency показывает рост p99 после деплоя. Но новый code path на 5% медленнее или на 50%? И какая функция изменилась? Дашборд не скажет. Дифференциальный профиль отвечает на оба вопроса: ширина красных фреймов — это серьёзность проблемы; имя фрейма и его родитель — это местонахождение. Команды, делающие автоматический diff профилей на каждый деплой, ловят регрессии за минуты, а не после жалобы клиента.

Викторина

Инженер читает flame graph и делает вывод, что функция A выполняется раньше B, потому что A стоит левее B на одном уровне. В чём ошибка?

Викторина

Только что прошёл деплой. Команда хочет узнать, было ли отклонение в CPU-производительности. Какой рабочий процесс профилирования наиболее прямой?

Вспомните перед уходом
  1. 01
    Объясни, почему x-ось flame graph алфавитная, а не временная, и какой инструмент использовать, если нужен порядок по времени.
  2. 02
    Что такое дифференциальный flame graph и какую проблему он решает?
  3. 03
    Назови три способа запрашивать профили как данные (помимо простого просмотра flame graph).
Итог

Flame graph строится агрегацией одинаковых стеков, их алфавитной сортировкой по корневой функции и отрисовкой прямоугольников с шириной, пропорциональной числу сэмплов. x-ось кодирует алфавитную группировку — никогда не время, — поэтому горизонтальная позиция фрейма не говорит ничего о порядке выполнения. Для порядка по времени используй timeline trace. Дифференциальные flame graph’ы накладывают два профиля (до и после деплоя) и окрашивают фреймы по изменению; это самый прямой способ поймать CPU-регрессии в момент деплоя. Профили — данные временного ряда: современные бэкенды поддерживают запросы по сервисам, diff по версии, группировку по ноде и alert на изменения формы, превращая profiling из инструмента отладки в непрерывный сигнал качества.

Связанные уроки
встречается в167
Продолжить восхождение ↑Linux perf, внутренности eBPF, PGO и ограничения sampling''''а
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.