pyroscope について
Grafana Pyroscope Skillは、コードレベルでアプリケーション性能を調べるための継続的プロファイリング基盤の導入・利用ガイドです。複数言語のプロファイル収集、保存、検索、Grafana連携を扱います。
主な機能
- 01コードレベルの継続的なプロファイル収集
- 02複数言語とプロファイル種別への対応
- 03モノリシックとマイクロサービスの導入形態
- 04オブジェクトストレージの設定
- 05Grafanaでのメトリクス、ログ、トレースとの関連付け
活用シーン
- 01アプリケーションのCPUやメモリ消費の特定
- 02Kubernetesへのプロファイリングサービス導入
- 03プロファイルデータのオブジェクトストレージ保存
- 04トレースと併せたコード性能の分析
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ julianobarbosa/ claude-code-skills --skill pyroscopeインストール後、Claude Code で/pyroscopeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/architecture.mdhelm-deployment.mdsdk-instrumentation.mdtroubleshooting.md詳細
Grafana Pyroscope スキル
Grafana Pyroscope の包括的なガイドです。コードレベルでアプリケーションのパフォーマンスを分析する、オープンソースの継続的プロファイリングプラットフォームです。
Pyroscope とは?
Pyroscope は、次の特長を備えた水平スケーラブルで高可用性のマルチテナント継続的プロファイリングシステムです。
- 最小限のオーバーヘッド(CPU の約 2~5%)でプロファイリングデータを継続的に収集します
- ソースコードの行単位の粒度でコードレベルの可視性を提供します
- 圧縮したプロファイルをオブジェクトストレージ(S3、GCS、Azure Blob)に保存します
- Grafana と統合し、プロファイルをメトリクス、ログ、トレースと関連付けます
- 複数の言語に対応しています。Go、Java、Python、.NET、Ruby、Node.js、Rust
アーキテクチャの概要
コアコンポーネント
| コンポーネント | 目的 |
|---|---|
| Distributor | 受信したプロファイルを検証し、Ingester にルーティングします |
| Ingester | プロファイルをメモリにバッファリングし、圧縮してストレージに書き込みます |
| Querier | 分析のためにプロファイルデータを取得して処理します |
| Query Frontend | クエリリクエスト、キャッシュ、スケジューリングを処理します |
| Query Scheduler | テナントごとのクエリキューを管理します |
| Store Gateway | 長期プロファイルストレージへのアクセスを提供します |
| Compactor | ブロックをマージし、保持期間を管理して、削除を処理します |
データフロー
書き込みパス:
SDK/Alloy → Distributor → Ingester → Object Storage
↓
Blocks + Indexes
読み取りパス:
Query → Query Frontend → Query Scheduler → Querier
↓
Ingesters + Store Gateway
デプロイモード
1. モノリシックモード(-target=all)
- すべてのコンポーネントが単一のプロセスで動作します
- 最適な用途:開発、小規模なデプロイ
- クエリ URL:
http://pyroscope:4040/
2. マイクロサービスモード(本番環境)
- 各コンポーネントが独立して動作します
- 水平スケーラブルです
- クエリ URL:
http://pyroscope-querier:4040/
# Microservices deployment
architecture:
microservices:
enabled: true
querier:
replicas: 3
distributor:
replicas: 2
ingester:
replicas: 3
compactor:
replicas: 3
storeGateway:
replicas: 3
クイックスタート - Kubernetes Helm
リポジトリを追加
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
シングルバイナリをインストール
kubectl create namespace pyroscope
helm install pyroscope grafana/pyroscope -n pyroscope
マイクロサービスモードをインストール
curl -Lo values-micro-services.yaml \
https://raw.githubusercontent.com/grafana/pyroscope/main/operations/pyroscope/helm/pyroscope/values-micro-services.yaml
helm install pyroscope grafana/pyroscope \
-n pyroscope \
--values values-micro-services.yaml
プロファイルの種類
| 種類 | 説明 | 言語 |
|---|---|---|
| CPU | ウォール時間/CPU 時間の消費量 | すべて |
| Memory | 割り当てオブジェクト/スペース、ヒープ | Go、Java、.NET |
| Goroutine | 並行実行される goroutine | Go |
| Mutex | ロック競合(回数/時間) | Go、Java、.NET |
| Block | スレッドのブロック/遅延 | Go |
| Exceptions | 例外の追跡 | Python |
クライアントの設定方法
方法 1:SDK によるインストルメンテーション(プッシュモード)
Go SDK:
import "github.com/grafana/pyroscope-go"
pyroscope.Start(pyroscope.Config{
ApplicationName: "my-app",
ServerAddress: "http://pyroscope:4040",
ProfileTypes: []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileAllocSpace,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileInuseSpace,
pyroscope.ProfileGoroutines,
pyroscope.ProfileMutexCount,
pyroscope.ProfileMutexDuration,
pyroscope.ProfileBlockCount,
pyroscope.ProfileBlockDuration,
},
Tags: map[string]string{
"env": "production",
},
})
Java SDK:
PyroscopeAgent.start(
new Config.Builder()
.setApplicationName("my-app")
.setServerAddress("http://pyroscope:4040")
.setProfilingEvent(EventType.ITIMER)
.setFormat(Format.JFR)
.build()
);
Python SDK:
import pyroscope
pyroscope.configure(
application_name="my-app",
server_address="http://pyroscope:4040",
tags={"env": "production"},
)
方法 2:Grafana Alloy(プルモード)
アノテーションによる自動インストルメンテーション:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
profiles.grafana.com/cpu.scrape: "true"
profiles.grafana.com/cpu.port: "8080"
profiles.grafana.com/memory.scrape: "true"
profiles.grafana.com/memory.port: "8080"
profiles.grafana.com/goroutine.scrape: "true"
profiles.grafana.com/goroutine.port: "8080"
Alloy の設定:
pyroscope.scrape "default" {
targets = discovery.kubernetes.pods.targets
forward_to = [pyroscope.write.default.receiver]
profiling_config {
profile.process_cpu { enabled = true }
profile.memory { enabled = true }
profile.goroutine { enabled = true }
}
}
pyroscope.write "default" {
endpoint {
url = "http://pyroscope:4040"
}
}
方法 3:eBPF プロファイリング(Linux)
コンパイル言語(C/C++、Go、Rust)向け:
pyroscope.ebpf "default" {
forward_to = [pyroscope.write.default.receiver]
targets = discovery.kubernetes.pods.targets
}
ストレージの設定
Azure Blob Storage
pyroscope:
config:
storage:
backend: azure
azure:
container_name: pyroscope-data
account_name: mystorageaccount
account_key: ${AZURE_ACCOUNT_KEY}
AWS S3
pyroscope:
config:
storage:
backend: s3
s3:
bucket_name: pyroscope-data
region: us-east-1
endpoint: s3.us-east-1.amazonaws.com
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}
Google Cloud Storage
pyroscope:
config:
storage:
backend: gcs
gcs:
bucket_name: pyroscope-data
# Uses GOOGLE_APPLICATION_CREDENTIALS
Grafana との統合
データソースの設定
apiVersion: 1
datasources:
- name: Pyroscope
type: grafana-pyroscope-datasource
access: proxy
url: http://pyroscope-querier:4040
isDefault: false
editable: true
トレースからプロファイルへのリンク
スパンプロファイルを有効にすると、トレースをプロファイルと関連付けられます。
OpenTelemetry を使用した Go:
import (
"github.com/grafana/pyroscope-go"
otelpyroscope "github.com/grafana/otel-profiling-go"
)
tp := trace.NewTracerProvider(
trace.WithSpanProcessor(otelpyroscope.NewSpanProcessor()),
)
要件:
- スパンの最小継続時間:20ms
- 対応言語:Go、Java、.NET、Python、Ruby
リソース要件
シングルバイナリ(開発)
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1
memory: 2Gi
マイクロサービス(本番環境)
| コンポーネント | CPU リクエスト | メモリリクエスト | メモリ制限 |
|---|---|---|---|
| Distributor | 500m | 256Mi | 1Gi |
| Ingester | 1 | 8Gi | 16Gi |
| Querier | 100m | 256Mi | 1Gi |
| Query Frontend | 100m | 256Mi | 1Gi |
| Compactor | 1 | 8Gi | 16Gi |
| Store Gateway | 1 | 8Gi | 16Gi |
Helm の一般的な値
# Production values
architecture:
microservices:
enabled: true
pyroscope:
persistence:
enabled: true
size: 50Gi
config:
storage:
backend: s3
s3:
bucket_name: pyroscope-prod
region: us-east-1
# High availability
ingester:
replicas: 3
terminationGracePeriodSeconds: 600
querier:
replicas: 3
distributor:
replicas: 2
compactor:
replicas: 3
terminationGracePeriodSeconds: 1200
storeGateway:
replicas: 3
# Pod disruption budget
podDisruptionBudget:
enabled: true
maxUnavailable: 1
# Topology spread
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
# Monitoring
serviceMonitor:
enabled: true
# Alloy for profile collection
alloy:
enabled: true
API エンドポイント
取り込み
# Push profiles (Connect API)
POST /push.v1.PusherService/Push
# Legacy HTTP (pprof, JFR formats)
POST /ingest
クエリ
# Merged profile
POST /querier.v1.QuerierService/SelectMergeProfile
# Flame graph data
POST /querier.v1.QuerierService/SelectMergeStacktraces
# Available labels
POST /querier.v1.QuerierService/LabelNames
# Profile types
POST /querier.v1.QuerierService/ProfileTypes
# Legacy render
GET /pyroscope/render?query={}&from=now-1h&until=now
システム
# Readiness
GET /ready
# Configuration
GET /config
# Metrics
GET /metrics
トラブルシューティング
診断コマンド
# Check pod status
kubectl get pods -n pyroscope -l app.kubernetes.io/name=pyroscope
# View ingester logs
kubectl logs -n pyroscope -l app.kubernetes.io/component=ingester --tail=100
# Check ring status
kubectl exec -it pyroscope-0 -n pyroscope -- \
curl http://localhost:4040/ingester/ring
# Verify readiness
kubectl exec -it pyroscope-0 -n pyroscope -- \
curl http://localhost:4040/ready
# Check configuration
kubectl exec -it pyroscope-0 -n pyroscope -- \
curl http://localhost:4040/config
よくある問題
1. Ingester の OOM:
ingester:
resources:
limits:
memory: 16Gi
2. ストレージの認証失敗:
# Azure - verify RBAC
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-object-id <principal-id> \
--scope <storage-scope>
3. カーディナリティの高いラベル:
# Limit label cardinality
pyroscope:
config:
validation:
max_label_names_per_series: 25
4. クエリのタイムアウト:
pyroscope:
config:
querier:
query_timeout: 5m
max_concurrent: 8
リファレンスドキュメント
トピック別の詳細な設定については、以下を参照してください。
- Helm デプロイ:Helm の values リファレンス全体
- アーキテクチャ:コンポーネントの詳細とスケーリング
- SDK インストルメンテーション:言語別 SDK ガイド
- トラブルシューティング:よくある問題と診断方法
外部リソース
注意点
- アプリケーションごとのプロファイルサンプリングレート:負荷の高いサービスでは、100Hz にすると無視できないオーバーヘッドが発生します。まずカナリアでプロファイリングしてください。
- ストレージのコンパクション中はマージ処理によって新しい書き込みがブロックされます:大規模なコンパクションは書き込みの停滞を引き起こすため、チャンクサイズとコンパクションウィンドウの調整が必要です。
- タグのカーディナリティの爆発:リクエストごとのタグはストレージを膨張させます。タグ値に明示的な上限を設けないと、ストレージは毎週倍増します。
- トレース連携:スパンとプロファイルのリンクには、エンドツーエンドで
traceparentヘッダーが伝播される必要があります。計装されていないホップが1つでもあると、リンクは通知なく失われます。 - eBPF プロファイラーと SDK プロファイラー:アトリビューションが異なり、競合する場合もあります。同じサービスで両方を実行しないでください。
- gRPC と HTTP プッシュ:データは同じですが、インジェスターでのレート制限が異なります。負荷がかかると、HTTP プッシュのほうが強くスロットリングされます。
コメント
Markdown 対応