Carpe Diem

備忘録

継続的プロファイリング

背景

過去にいくつかpprofの使い方を紹介しましたが、実際に運用する上では以下の課題があります。

  • 何かしら問題が発生して初めてプロファイリング開始するという後手になりがち
  • 問題の再現が難しく、再び発生するまで様子見という流れになりがち
  • プロファイリングしたことがないメンバーにとってオペレーションコストが高い
  • バージョン比較ができない

これらの課題を解決するために、継続的プロファイリング(Continuous Profiling)を導入します。

環境

継続的プロファイリングとは

継続的にpprofのようなプロファイリングを行い、可視化も含め実運用で効果的に活用できるようにすることです。

パブリッククラウドや監視サービスがすでにサービスとして提供しているので、自前で構築しなくてもそれらを利用できます。

ソリューション

各社が継続的プロファイリングのサポートをしています。

会社 サービス名
GCP Cloud Profiler
AWS Amazon CodeGuru
DataDog Continuous Profiler

OSSだとprofefeというツールがあります。

github.com

メトリクスとプロファイリングの違い

オブザーバビリティにおけるプロファイルの重要性 pprofを活用するメリットをGoogle CloudのDeveloper Advocateが語る - ログミーTech

こちらで分かりやすく説明されています。ざっとまとめると以下です

共通点

  • カバーしている領域が同じ
  • サンプリングする

異なる点

メトリクス プロファイリング
自分で取りたいデータを定義 あらかじめ定義されたもの
(CPU, RAM, threads)
サンプリング期間が短い サンプリング期間が長い
時系列データ スタックトレースと相関のある統計データ

導入してみる

GCPのCloud Profilerを用いて検証してみましょう。
Cloud Profilerは

  • 無料
  • 導入が容易
  • パフォーマンス影響なし

と良いこと尽くめです。

Profiler API を有効にする

以下のコマンドで有効化してください。

$ gcloud services enable cloudprofiler.googleapis.com

コードの修正

できるだけmain関数の早い位置で以下のようにprofilerを開始してください。

func main() {
        cfg := profiler.Config{
                Service:        "my-service",  // サービス名
                ServiceVersion: config.BuildVersion,  // バイナリビルド時にgithubのtagを埋め込む
                MutexProfiling: true,
        }
        if err := profiler.Start(cfg); err != nil {
                log.Panic("Profiler failed to start", log.Ferror(err))
        }
        ...
}

profiler.Start()は内部でgoroutineを走らせるので、この処理はノンブロッキングです。

UI

しばらく稼働していると以下のようにWebコンソールで表示されるようになります。

CPU

f:id:quoll00:20201126111344p:plain

メモリ

f:id:quoll00:20201126111125p:plain

デフォルトではフレームの色は関数のパッケージに対応しています。

バージョン比較

Cloud Profilerではconfigに設定したバージョンを使った比較が可能です。

f:id:quoll00:20201126112200p:plain

色については以下のように定義されています。

  • 灰色: 違いがほとんどないか、まったくないことを表す
  • 赤: 違いが正の値(消費が増えた)であることを表す
  • 青: 違いが負の値(消費が減った)であることを表す

今回の画像を見ると少し青みがかっているので、対象としたバージョンよりも少しばかり改善されていると解釈できます。

まとめ

継続的プロファイリングの重要性、導入方法を説明しました。
ぜひ導入して定期的にチェックすることで、システムのパフォーマンス改善をしていきましょう。

参考