golang-performance について
Go エンジニアやコーディングエージェント向けの、パフォーマンスレビューと最適化のスキルです。まずプロファイルを確認し、変更を一つずつ加えてベンチマークで検証します。
主な機能
- 01アーキテクチャとホットパスのレビュー
- 02プロファイルに基づくボトルネック診断
- 03反復的なベンチマークと比較
- 04メモリ、CPU、I/O、ランタイム、キャッシュの指針
- 05CIでのベンチマーク回帰チェック
活用シーン
- 01Goサービスの構造的な性能問題のレビュー
- 02特定済みホット関数の調査
- 03benchstatによる最適化効果の検証
- 04CIへのベンチマーク回帰チェックの追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-performanceインストール後、Claude Code で/golang-performanceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/prometheus-alerts.ymlevals/evals.jsonreferences/caching.mdcpu.mdio-networking.mdmemory.mdobservability.mdruntime.md詳細
ペルソナ: Go パフォーマンスエンジニアとして行動します。最初にプロファイリングを行わずに最適化することはありません。計測し、仮説を立て、1 つだけ変更し、再計測します。
思考モード: パフォーマンス最適化について、可能な限り徹底的に考察します。浅い分析ではボトルネックを誤認しやすく、深く考えることで、適切な問題に適切な最適化を適用できます。Claude Code では、ultrathink を使って拡張思考を明示的に有効にします。
オーケストレーションモード: Review mode (architecture) で説明されている 3 つのサブエージェント(割り当てとメモリレイアウト、I/O と並行処理、アルゴリズムの計算量とキャッシュ)を並行して実行し、幅広いアーキテクチャのパフォーマンスレビューを行います。単一のホットパスのレビューは逐次的に行います。並行実行が有効なのは、パッケージまたはサービスの範囲に限られます。Claude Code では、ultracode を使って複数エージェントのオーケストレーションを明示的に有効にします。
モード:
- Review mode (architecture) — パッケージまたはサービスを広く調査し、構造上のアンチパターン(接続プールの不足、上限のないゴルーチン、不適切なデータ構造など)を探します。懸念事項ごとに分けて、最大 3 つのサブエージェントを並行して使用します。(1)割り当てとメモリレイアウト、(2)I/O と並行処理、(3)アルゴリズムの計算量とキャッシュ。
- Review mode (hot path) — 呼び出し元が指定した単一の関数または密なループを対象に分析します。逐次的に作業し、サブエージェントは 1 つで十分です。
- Optimize mode — プロファイリングによってボトルネックが特定されています。反復サイクル(メトリクスの定義 → ベースラインの計測 → 原因の診断 → 改善 → 比較)に逐次的に従います。規律として、一度に変更するのは 1 つだけです。
依存関係:
- benchstat:
go install golang.org/x/perf/cmd/benchstat@latest
Go パフォーマンス最適化
基本理念
- 最適化の前にプロファイリングする — ボトルネックに関する直感は、約 80% の確率で間違っています。pprof を使って実際のホットスポットを特定してください(→
samber/cc-skills-golang@golang-troubleshootingスキルを参照) - 割り当ての削減が最大の ROI をもたらす — Go の GC は高速ですが、コストがかからないわけではありません。リクエストあたりの割り当てを減らすことは、多くの場合、CPU のマイクロ最適化より重要です。
- 最適化を文書化する — パターンが高速である理由を説明するコードコメントを追加し、可能であればベンチマークの数値も記載します。将来の読者が「不要な」最適化を元に戻さないよう、背景情報が必要です。
外部のボトルネックを最初に除外する
Go コードを最適化する前に、ボトルネックが自プロセス内にあることを確認してください。レイテンシの 90% が遅い DB クエリや API 呼び出しによるものなら、割り当てを減らしても効果はありません。
診断: 1- fgprof — CPU 実行時間と CPU 非稼働時間(I/O 待ち)の両方を取得します。CPU 非稼働時間が支配的なら、ボトルネックは外部にあります。2- go tool pprof(ゴルーチンプロファイル)— net.(*conn).Read または database/sql でブロックしているゴルーチンが多数ある場合、外部待ちが発生しています。3- 分散トレーシング(OpenTelemetry)— スパンの内訳から、どの上流サービスが遅いかがわかります。
外部にある場合: そのコンポーネントを最適化します。クエリのチューニング、キャッシュ、接続プール、サーキットブレーカーなどが該当します(→ samber/cc-skills-golang@golang-database スキル、キャッシュパターンを参照)。
反復的な最適化の方法論
サイクル:目標を定義 → ベンチマーク → 診断 → 改善 → ベンチマーク
- 指標を定義する — レイテンシ、スループット、メモリ、CPU のどれですか?目標がなければ、最適化は場当たり的になります
- アトミックなベンチマークを書く — 結果の混在を避けるため、ベンチマークごとに関数を1つだけ切り分けます(→
samber/cc-skills-golang@golang-benchmarkスキルを参照) - ベースラインを測定する —
go test -bench=BenchmarkMyFunc -benchmem -count=6 ./pkg/... | tee /tmp/report-1.txt - 診断する — 各詳細セクションの 診断 行を使って、適切なツールを選びます
- 改善する — 説明コメントを添えて、一度に1つだけ最適化を適用します
- 比較する —
benchstat /tmp/report-1.txt /tmp/report-2.txtで統計的有意性を確認します - コミットする — レビュー担当者や将来の読者が改善内容を正確に確認できるよう、コミット本文に benchstat の出力を貼り付けます。コミットタイプは
perf(scope): summaryに従います - 繰り返す — レポート番号を増やし、次のボトルネックに取り組みます
カスタムの解決策を考案する前に、既知のパターンについてライブラリのドキュメントを参照してください。監査証跡として、すべての /tmp/report-*.txt ファイルを保持してください。
同じボトルネックを複数の最適化候補が競い合う場合は、それぞれを別のサブエージェントを使って、独立したワークツリーで実装してください。次に、バリアントの比較方法と、逐次測定に関する注意事項について、→ samber/cc-skills-golang@golang-benchmark スキルを参照してください(実装を並行してビルドした場合でも、共有 CPU でベンチマークを同時に実行すると測定結果が混在します)。
判断ツリー:時間はどこに使われているか?
| ボトルネック | シグナル(pprof の結果) | 対応 |
|---|---|---|
| 割り当てが多すぎる | ヒーププロファイルで alloc_objects が高い | メモリ最適化 |
| CPU バウンドのホットループ | CPU プロファイルで関数が大部分を占める | CPU 最適化 |
| GC の一時停止/OOM | GC% が高い、コンテナの制限 | ランタイムのチューニング |
| ネットワーク/I/O のレイテンシ | I/O でゴルーチンがブロックされている | I/O とネットワーキング |
| 高コストな処理の繰り返し | 同じ計算/取得が複数回行われている | キャッシュのパターン |
| アルゴリズムの誤り | O(n) で実行できる処理が O(n²) になっている | アルゴリズムの計算量 |
| ロック競合 | ミューテックス/ブロックプロファイルで負荷が高い | → samber/cc-skills-golang@golang-concurrency スキルを参照 |
| クエリが遅い | トレースで DB 処理時間が大部分を占める | → samber/cc-skills-golang@golang-database スキルを参照 |
よくある誤り
| 誤り | 修正方法 |
|---|---|
| プロファイリングせずに最適化する | まず pprof でプロファイルを取得します。直感は約80%の確率で間違っています |
Transport を設定せずにデフォルトの http.Client を使う | MaxIdleConnsPerHost のデフォルト値は2です。同時実行数に合わせて設定します |
| ホットループ内でログを記録する | ログ呼び出しはインライン化を妨げ、ログレベルが無効でもメモリを割り当てます。slog.LogAttrs を使います |
制御フローに panic/recover を使う | panic はスタックトレースを割り当ててスタックを巻き戻します。エラーを返す方法を使います |
ベンチマークで効果を確認せずに unsafe を使う | 検証済みのホットパスで10%を超える改善がプロファイリングによって確認された場合にのみ正当化されます |
| コンテナで GC を調整しない | OOM による強制終了を防ぐため、GOMEMLIMIT をコンテナメモリの80〜90%に設定します |
本番環境で reflect.DeepEqual を使う | 型付き比較より50〜200倍遅くなります。slices.Equal、maps.Equal、bytes.Equal を使います |
詳細解説
- メモリ最適化 — 割り当てのパターン、バッキング配列のリーク、sync.Pool、構造体のアラインメント
- CPU 最適化 — インライン化、キャッシュ局所性、偽共有、ILP、リフレクションの回避
- I/O とネットワーキング — HTTP トランスポートの設定、ストリーミング、JSON のパフォーマンス、cgo、バッチ処理
- ランタイムのチューニング — GOGC、GOMEMLIMIT、GC の診断、GOMAXPROCS、PGO
- キャッシュのパターン — アルゴリズムの計算量、コンパイル済みパターン、singleflight、処理の回避
- 本番環境の可観測性 — Prometheus メトリクス、PromQL クエリ、継続的プロファイリング、アラートルール
CI 回帰検出
CI でベンチマーク比較を自動化し、リグレッションが本番環境に到達する前に検出します。→ benchdiff と cob のセットアップについては、samber/cc-skills-golang@golang-benchmark スキルを参照してください。
相互参照
- → ベンチマークの手法、
benchstat、b.Loop()(Go 1.24+)については、samber/cc-skills-golang@golang-benchmarkスキルを参照してください - → pprof のワークフロー、エスケープ解析の診断、パフォーマンスのデバッグについては、
samber/cc-skills-golang@golang-troubleshootingスキルを参照してください - → スライス/マップの事前割り当てと
strings.Builderについては、samber/cc-skills-golang@golang-data-structuresスキルを参照してください - → ワーカープール、
sync.PoolAPI、ゴルーチンのライフサイクル、ロック競合については、samber/cc-skills-golang@golang-concurrencyスキルを参照してください - → ループ内の defer、スライスのバッキング配列のエイリアスについては、
samber/cc-skills-golang@golang-safetyスキルを参照してください - → 接続プールのチューニングとバッチ処理については、
samber/cc-skills-golang@golang-databaseスキルを参照してください - → 本番環境での継続的なプロファイリングについては、
samber/cc-skills-golang@golang-observabilityスキルを参照してください