How grafana/pyroscope works
Purpose and entry points
Grafana Pyroscope is a Go-based, multi-tenant continuous-profiling backend. It receives pprof/Pyroscope and OTLP profiles, persists and compacts them, and serves profile-analysis queries for Grafana and its embedded UI. The primary server binary is cmd/pyroscope/main.go, which initializes the module graph in pkg/pyroscope/pyroscope.go and pkg/pyroscope/modules.go. cmd/profilecli/main.go is the operational/query CLI.
Deployment and module composition
One binary supports single-binary and microservices deployment modes; Helm renders both, including v2 variants: operations/pyroscope/helm/pyroscope/templates/unified-services.yaml, operations/pyroscope/helm/pyroscope/rendered/micro-services-v2.yaml, and operations/pyroscope/helm/pyroscope/rendered/single-binary-v2.yaml. Modules expose HTTP and Connect/gRPC-style APIs, use tenant middleware, rings/service discovery where required, and can be independently scaled in microservice mode.
Ingestion and v2 write path
Clients/Alloy/OpenTelemetry send profiles through API handlers and the distributor. The distributor applies tenancy, validation/limits, sampling/aggregation, and routes writes by service: pkg/distributor/distributor.go, pkg/distributor/writepath/router.go, pkg/distributor/aggregator/aggregator.go. In default v2, profiles are sent to segment writers rather than resident ingesters; segment writers maintain a short-lived in-memory segment and write it directly to object storage: pkg/segmentwriter/service.go, pkg/segmentwriter/segment.go, pkg/segmentwriter/memdb/head.go.
Storage, metadata, and compaction
The v2 durable boundary is object storage. Storage adapters support filesystem, S3, GCS, Azure, Swift, and COS through pkg/objstore/client/factory.go, pkg/objstore/providers/s3/bucket_client.go, and pkg/objstore/providers/gcs/bucket_client.go. Segments and compacted blocks use a block format with profile data, TSDB indexing, Parquet, and symbol databases: pkg/block/block.go, pkg/phlaredb/schemas/v1/profiles.go, pkg/phlaredb/symdb/symdb.go.
The metastore maintains distributed metadata/index/compaction state using Raft and BoltDB-backed FSM persistence: pkg/metastore/metastore.go, pkg/metastore/raftnode/node.go, pkg/metastore/fsm/boltdb.go. It schedules work; compaction workers merge segments into larger blocks and publish metadata: pkg/metastore/compaction/scheduler/scheduler.go, pkg/compactionworker/worker.go, pkg/block/compaction.go.
Read path and query execution
The query frontend accepts profile, labels, time-series, diff, heatmap, and stacktrace requests, splits/routs work and merges responses: pkg/frontend/readpath/read_path.go, pkg/frontend/readpath/queryfrontend/query_frontend.go, pkg/frontend/frontend_select_merge_profile.go. The query backend obtains relevant blocks from metastore metadata, reads object-store blocks, executes parallel plans, and aggregates profile trees/reports: pkg/querybackend/backend.go, pkg/querybackend/queryplan/query_plan.go, pkg/querybackend/block_reader.go. Store gateway provides sharded/cached access to persisted blocks: pkg/storegateway/gateway.go, pkg/storegateway/query.go.
Legacy v1 compatibility
The repository retains the v1 ingestion/query architecture for migration and compatibility. Distributors route to replicated, ring-managed ingesters; ingesters retain/query local head data and ship blocks; queriers combine ingester and store-gateway results. Core paths are pkg/ingester/ingester.go, pkg/querier/querier.go, and pkg/phlaredb/shipper/shipper.go. This is architecturally distinct from v2’s direct-to-object-store write path.
Interfaces and presentation
Public contracts are protobuf-first and generated into Connect bindings/OpenAPI documents: api/push/v1/push.proto, api/query/v1/query.proto, and api/gen/proto/go/query/v1/queryv1connect/query.connect.go. Server route registration and legacy HTTP surface are centralized in pkg/api/api.go. The React/TypeScript UI is built separately, embedded into the Go server, and calls these APIs: ui/src/main.tsx, ui/src/api/client.ts, and ui/assets_embedded.go. Optional source lookup integrates with GitHub and debuginfod-based symbol resolution: pkg/frontend/vcs/github.go, pkg/symbolizer/debuginfod_client.go.
Main entry points: api.go API routes · factory.go Object storage · metastore.go Metastore · distributor.go Distributor
Components 19
Entrypoints
- Pyroscope server · Runs selected modules in monolithic or microservice mode.
cmd/pyroscope/main.go - Module graph
pkg/pyroscope/modules.go - profilecli
cmd/profilecli/main.go - Helm deployment modes
operations/pyroscope/helm/pyroscope/templates/unified-services.yaml
V2 write and storage
- Distributor · Applies limits, sampling, aggregation, and service routing.
pkg/distributor/distributor.go - V2 write router
pkg/distributor/writepath/router.go - Segment writer · Builds an in-memory segment and writes it directly to object storage.
pkg/segmentwriter/service.go - Object storage · Filesystem and cloud bucket providers implement the durable boundary.
pkg/objstore/client/factory.go - Block format
pkg/block/block.go - Metastore · Persists distributed block metadata, index state, and compaction state.
pkg/metastore/metastore.go - Compaction workers · Merge segments into blocks and publish metadata.
pkg/compactionworker/worker.go
Read and query
- Query frontend · Routes profile-analysis requests and merges partial responses.
pkg/frontend/readpath/queryfrontend/query_frontend.go - Query backend · Plans block reads and aggregates profile trees and reports.
pkg/querybackend/backend.go - Store gateway · Provides cached access to persisted blocks.
pkg/storegateway/gateway.go
V1 compatibility
- V1 ingester · Retains local head data and ships blocks.
pkg/ingester/ingester.go - V1 querier · Combines ingester and store-gateway results.
pkg/querier/querier.go
Contracts and UI
- API routes
pkg/api/api.go - Profile query contracts
api/query/v1/query.proto - Embedded React UI
ui/src/main.tsx
Connections 25
- Helm deployment modes → Pyroscope server: deploys
- Pyroscope server → Module graph: initializes
- Module graph → API routes: registers
- profilecli → API routes: queries
- Embedded React UI → API routes: calls
- Profile query contracts → API routes: defines
- API routes → Distributor: ingest requests
- Distributor → V2 write router: routes v2 writes
- V2 write router → Segment writer: assigns
- Segment writer → Object storage: writes segments
- Segment writer → Metastore: publishes metadata
- Object storage → Block format: stores
- Metastore → Compaction workers: schedules
- Compaction workers → Object storage: writes compacted blocks
- Compaction workers → Metastore: publishes blocks
- API routes → Query frontend: analysis requests
- Query frontend → Query backend: splits and routes
- Query backend → Metastore: looks up blocks
- Query backend → Store gateway: reads blocks
- Store gateway → Object storage: loads cached shards
- Distributor → V1 ingester: legacy replicated writes
- V1 ingester → Object storage: ships blocks
- V1 querier → V1 ingester: reads head data
- V1 querier → Store gateway: reads persisted data
- API routes → V1 querier: legacy queries