linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • Симулятор
  • База знаний
  • Собеседование
Index
Categories
All entries
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
home/linux/kb/Observability и мониторинг/pyroscope-continuous-profiling

kb/observability ── Observability и мониторинг ── advanced

Continuous profiling: Pyroscope, eBPF, flame graphs в проде

Continuous profiling - always-on CPU/memory profiler в проде через eBPF. 1-2% overhead. Flame graphs показывают hot path. Pyroscope (Grafana), Parca, Polar Signals. Замена ad-hoc perf для production debug.

view as markdownaka: pyroscope, continuous-profiling, flame-graphs, ebpf-profiler, parca

Зачем continuous profiling

Классический profiling, Brendan Gregg-style: SSH на хост, perf record, perf script | flamegraph.pl. Hassle:

  • Реактивно (после инцидента, обычно поздно)
  • Один хост, один процесс
  • Snapshot, не trends
  • Требует root, sudo, debug symbols on disk
  • Overhead в момент замера ~5-10% CPU

Continuous profiling, always-on profiler в каждом узле, sample ~100 Hz, оверхед 1-2% CPU, шлёт в central storage. Появилось ~2020 (Google "Continuous Profiling" paper, Pyroscope).

Что даёт:

  • Постоянные flame graphs, открыл Grafana, видишь где CPU тратится прямо сейчас, или 2 недели назад
  • Diff между версиями, flame graph до/после релиза, увидеть регрессию
  • Correlation с метриками, alert «p99 latency растёт» → сразу видишь stack где это
  • Root-cause за минуты, не за дни

В 2025, production-tool в Cloudflare, Polar Signals, Coinbase, Pinterest. Самые заметные runtime регрессии находят профайлингом.

Как работает eBPF profiler

Старый perf: kernel-ring-buffer, perf_event_open, sample на каждом CPU через PMU (timer interrupt). Stack walk через frame pointers или DWARF.

eBPF profiler ([[ebpf-basics|eBPF]]), eBPF программа атачится к perf event (sample 100 Hz):

int profile(struct bpf_perf_event_data *ctx) {
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    u64 *count = bpf_map_lookup_elem(&counts, &pid);
    bpf_get_stack(ctx, stack, sizeof(stack), 0);     // kernel stack
    bpf_get_stack(ctx, stack, sizeof(stack), USER);  // user stack
    // aggregate in BPF map
}

Преимущества:

  • Frame-pointer-free stack walking (DWARF unwinding в eBPF, в последних ядрах)
  • Per-cgroup filtering, profiles per Kubernetes pod без знания PID
  • Symbolization on-host, eBPF читает /proc/PID/maps, находит ELF, extract symbols
  • CO-RE ([[bpf-co-re|BPF Compile Once Run Everywhere]]), один binary на разные ядра

Flame graphs, как читать

Каждый rectangle, функция. Width = доля CPU time. Y-axis call stack (parent внизу, children сверху).

┌─────────────────────────────────────────────┐
│                  main()                     │
├─────────────────┬───────────────────────────┤
│  serve_request  │      gc_collect           │
├──────────┬──────┼─────────────┬─────────────┤
│  parse   │ db   │  sweep_old  │ allocate    │
├──┬───────┼──────┼─────────────┼─────────────┤
│j │ regex │ scan │             │             │
└──┴───────┴──────┴─────────────┴─────────────┘

«regex занимает 25% CPU всего процесса». Если плато широкое и плоское, leaf hot. Если высокое и узкое, глубокий call stack без plateau, обычно нормально.

Flame graph самплируется, не traces, точные числа неточны (±5%), но пропорции верные.

Pyroscope architecture

┌───────────────┐   pull profiles    ┌──────────────┐
│  Pyroscope    │ ─────────────────► │   target     │
│  server       │                    │ (with eBPF   │
│ ┌───────────┐ │                    │  profiler    │
│ │ TSDB-like │ │                    │  agent)      │
│ │ profiles  │ │                    └──────────────┘
│ │  store    │ │                    ┌──────────────┐
│ └───────────┘ │ ◄───── push ────── │   target     │
│ ┌───────────┐ │                    │ (with SDK    │
│ │ Querier   │ │ ◄─── Grafana       │  push agent) │
│ └───────────┘ │       UI           └──────────────┘
└───────────────┘

Storage похож на [[prometheus-basics|Prometheus TSDB]]: profile per (service, instance) per timestamp. Query, flame graph за range с filter по labels.

Два режима ingest:

  • Pull eBPF agent (DaemonSet), single agent профилирует всё на хосте без SDK. Best для k8s.
  • Push SDK, runtime-specific (Java, Go, Python). Точнее для managed runtimes (Java JIT-frames eBPF не видит).

Labels, каждый profile тегирован

Как и Prometheus, labels определяют series:

service.name=checkout
pod=checkout-7f8b9c-q2lx9
namespace=prod
region=us-east-1
version=1.4.2

Можно фильтровать в UI: «flame graph для version=1.4.2 vs 1.4.1», «diff between region=us-east vs us-west». Это и есть мощь, slice по label, найти аномалию.

Cardinality правила те же: pod, десятки тысяч, OK с retention. request_id, никогда.

Profile types

Pyroscope/Parca собирают разные типы:

TypeЧто показывает
process_cpuon-CPU sampling - где время CPU
goroutine (Go)живые goroutines - leak detection
inuse_space (Go heap)currently alloc'd memory
alloc_space (Go heap)total allocated since start
block (Go)blocking on chan/mutex
mutex (Go)contention
wall_clockwall-time (включая sleep, IO wait) - что блокирует
lock_contention (Java)JFR-based

Для Java auto-magic через [[opentelemetry|OpenTelemetry profiling]]

  • JFR (Java Flight Recorder).

Pyroscope vs Parca vs Polar Signals

ToolBackendStorageМаркетинг
PyroscopeGrafana Labs (acq 2023)own TSDB-likeOSS, integrated с Grafana
ParcaPolar SignalsownOSS, Parquet-on-S3
Polar Signals Cloudhostedproprietary$$ paid
GProfilerGranulate (acq Intel)ownавтоматическая ARM/x86

Pyroscope, recommended для самохоста с Grafana stack. Parca, если хочется parquet-friendly query через DuckDB/SQL.

Continuous profiling vs traditional perf

Свойствоperf recordcontinuous profiler
Whenad-hoc (после инцидента)always-on
Overhead5-10% во время записи1-2% постоянно
Storagelocal file (perf.data)central, retention
Symbolizationlocallyon-agent + central
Multi-hostнетда, per-pod
Diff между датамивручную через foldedUI feature
Stack accuracyDWARF + perfeBPF + DWARF/frame-pointers

CPU profiling vs memory

Для CPU bottleneck, process_cpu тип, sample @100Hz, hot path.

Для memory leak, alloc_space (Go heap-profiler) или Java JFR Allocation* events. Видно где аллоцируется мусор, что после GC растёт.

Memory profiling overhead выше (~3-5%), не always-on в проде. Включай по запросу или при memory.high triggered ([[cgroups-v2-deep|cgroup PSI]]).

Profile-Guided Optimization (PGO)

Go 1.21+, Rust nightly: компилятор берёт production profile как hint, оптимизирует hot code (better inlining, branch prediction).

Workflow:

  1. Continuous profiling в проде → собрал default.pgo
  2. Положил в репо рядом с main.go
  3. go build подхватывает PGO профиль
  4. Speedup 2-15% на типичный Go-сервис

Pyroscope есть pyroscope-pgo exporter для этого.

Когда что-то пошло не так

  • Stack «[unknown]», нет debug symbols или frame pointers отсутствуют (gcc default -fomit-frame-pointer). Build с -fno-omit-frame-pointer или enable DWARF unwinding в profiler.
  • Java stack frames пустые, JIT compilation, нужен JFR-based instead of pure eBPF.
  • High cardinality, каждый pod = новый series. Лимит retention или drop pod label, оставь deployment.
  • Profiles не приходят, eBPF agent требует CAP_SYS_ADMIN + CAP_BPF (bpf-co-re). На k8s, securityContext.privileged или подходящие capabilities.
  • Дельта между версиями странная, разные [[cgroups-v2-deep|cgroup PSI throttling]] изменили execution time, не код. Контролируй test environment.
  • Async/await stacks разорваны, Go goroutine, Rust async. Pyroscope Go SDK + ebpf делают это, Python asyncio, partially.

Когда НЕ использовать

  • Маленький сервис < 10K rps, overhead 1-2% незаметен, но и проблем найти нечего. Просто pprof ad-hoc хватает.
  • Compliance запрещает читать stack trace production data (PII в strings), не используй sampling string captures.
  • Embedded, IoT, нет ресурсов на eBPF agent.

§ команды

bash
pyroscope agent --target-pid=$(pgrep -f myapp) --tag=service=myapp

Pyroscope eBPF agent на конкретный PID - быстрая проверка

bash
curl -s 'http://pyroscope:4040/render?query=process_cpu{service="checkout"}&from=now-1h&until=now&format=collapsed' | head -20

Сырые folded stacks (формат для FlameGraph.pl) для query 'CPU usage of checkout'

bash
go tool pprof -http=:8080 'http://pyroscope:4040/render?query=process_cpu{...}&format=pprof'

Открыть Pyroscope профиль в `go tool pprof` локально

bash
perf record -F 99 -g -p $(pgrep myapp) -- sleep 30

Классический perf для сравнения с eBPF-based - 99Hz, 30 сек

bash
parca-agent --node=$NODE --kubernetes --metadata-external-labels=cluster=prod

Parca agent на k8s node - DaemonSet-style deploy

bash
go test -cpuprofile=cpu.prof ./... && go tool pprof -http=: cpu.prof

On-demand pprof в Go - локально для bench, не для prod

bash
OTEL_EXPORTER_OTLP_PROFILES_ENDPOINT=http://collector:4318 java -javaagent:opentelemetry-javaagent.jar -jar app.jar

OTel Java agent с profiling-enabled (experimental в OTel 1.30+)

§ см. также

  • ebpf-basicseBPF - программируемый kerneleBPF - запуск sandboxed-программ в kernel без kernel-modules. Прицепляются к hooks (kprobe, uprobe, tracepoint, perf, socket, XDP). Verifier гарантирует завершение и safety. JIT компилирует в native. bpftool/libbpf/BCC - userspace tooling.
  • bpf-co-reBPF CO-RE - Compile Once Run EverywhereCO-RE - один скомпилированный eBPF-объект работает на разных kernel благодаря BTF (BPF Type Format). vmlinux.h - dump структур ядра. libbpf на runtime перезаписывает offsets. Заменяет BCC, не нужен LLVM в проде.
  • cgroups-v2-deepcgroups v2 - unified hierarchy, PSI, eBPF controlcgroups v2 - один tree вместо отдельных hierarchies на controller. Чистая семантика, новые fields (memory.high, io.cost). PSI показывает resource pressure. eBPF может управлять resources. Default в RHEL 9, Ubuntu 22+.
  • prometheus-basicsPrometheus: scrape, TSDB, PromQL и production-pitfallsPrometheus - сервер мониторинга: сам опрашивает приложения по HTTP, собирает числовые метрики, хранит во встроенной БД ~15 дней. По ним строят графики в Grafana и алерты через Alertmanager. Стандарт de-facto в Kubernetes.
  • opentelemetryOpenTelemetry: signals, OTLP, Collector pipelineOpenTelemetry - CNCF-стандарт для metrics+traces+logs в одном SDK. OTLP протокол (gRPC или HTTP). Collector принимает, фильтрует, роутит в Prom/Tempo/Loki/Jaeger. Auto-instrumentation без code change.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки