Brendan Greggの実用的な手法(USE、RED、フレームグラフ)を使って、推測ではなくデータでレイテンシや本番のボトルネックを調査する方法を学びます。

Brendan Greggは特にLinux界隈でシステムパフォーマンスに関する最も影響力のある人物の一人です。広く使われている書籍を執筆し、実用的なツール群を作り、そして何より、実際の本番問題を調査するための明確な手法を共有してきました。チームが彼のアプローチを採用する理由は、プレッシャー下でも機能するからです。レイテンシが急上昇して全員が答えを求めるとき、余計な混乱を避けつつ「多分Xだ」から「確実にYだ」へ移る方法が必要です。
パフォーマンス手法とは、単一のツールや巧妙なコマンドではありません。調査を繰り返し行える方法、つまり最初に何を確認するか、見たものをどう解釈するか、次に何をするかを決めるチェックリストです。
この反復可能性こそが推測を減らします。最も直感的な人(または最も声が大きい人)に頼る代わりに、次のような一貫したプロセスに従います:
多くのレイテンシ調査は最初の5分で誤った方向に進みます。人々はすぐに修正に飛びつきます:"CPUを増やせ"、"サービスを再起動せよ"、"キャッシュを増やせ"、"GCを調整せよ"、"ネットワークに違いがあるに違いない"。時にはその対応が有効なこともありますが、多くの場合は信号を隠したり時間を浪費したり、新たなリスクを生みます。
Greggの手法は「解決策」を遅らせ、次のようなシンプルな質問に答えられるように促します:何が飽和しているのか?何がエラーを出しているか?スループット、待ち行列、個々の操作のどれが遅くなったのか?
このガイドは、範囲を絞り、適切な指標を計測し、最適化する前にボトルネックを確認するのを助けます。目的は本番でのレイテンシとプロファイリング問題を調査するための構造化されたワークフローを提供し、結果が運任せにならないようにすることです。
レイテンシは「症状」です:ユーザーが作業の完了を待つ時間が長くなります。原因は通常別の場所にあり—CPU競合、ディスクやネットワークの待ち、ロック競合、ガベージコレクション、待ち行列、リモート依存先の遅延などです。レイテンシだけを計測しても、痛みがどこから来ているかはわかりません。
これら3つの指標は結びついています:
チューニング前に、同じ時間窓についてこれら3つをすべて取得してください。さもないと、作業を落としたり故意に速く失敗させてレイテンシを“修正”することになりかねません。
平均レイテンシはユーザーが記憶するスパイクを隠します。50msの平均を持つサービスでも頻繁に2秒の停止が起こることがあります。
パーセンタイルを追跡しましょう:
またレイテンシの形状を監視してください:p50が安定しているのにp99が上昇している場合、断続的なスタール(ロック競合、I/Oの小さな停滞、stop-the-worldの一時停止など)を示すことが多いです。
レイテンシ予算は単純な会計モデルです:「リクエストが300msで終わらなければならないなら、時間はどこに使えるか?」次のようなバケットに分けます:
この予算は最初の計測タスクの枠組みになります:スパイク時にどのバケットが増えたかを特定し、その領域を調査して盲目的にチューニングするのを避けます。
「システムが遅い」とだけ描写されるとレイテンシの作業は脱線します。Greggの手法はもっと早い段階で始めます:問題を特定の、テスト可能な質問に落とし込むのです。
ツールに触る前に2文書き出してください:
これにより、痛みが特定のエンドポイントや下流依存に限定されているのにホストCPUを最適化する、といった誤った層の最適化を防げます。
苦情に合う時間窓を選び、可能なら“良好”な比較期間も含めます。
調査のスコープを明確に定義してください:
ここで正確にすると、後のUSE、RED、プロファイリングのステップが速くなります。どのデータが動くべきかがわかっているからです。
デプロイ、設定変更、トラフィックの変化、インフライベントをメモしつつ、因果を仮定しないでください。これらは「もしXならばYが起きるだろう」といった仮説として書き、迅速に確認または否定できるようにします。
小さなログがあればチーム内の重複作業を防ぎ、引き継ぎがスムーズになります。
Time | Question | Scope | Data checked | Result | Next step
5行ほどの記録でも緊張するインシデントを再現可能なプロセスに変えられます。
USEメソッド(Utilization, Saturation, Errors)は、Greggの「大きな4つ」リソース(CPU、メモリ、ディスク(ストレージ)、ネットワーク)を走査するためのクイックチェックリストです。推測をやめ、問題を絞るために使います。
多数のダッシュボードを眺める代わりに、各リソースに対して同じ3つの質問を投げます:
一貫して適用すれば、どこに“圧力”がかかっているかを素早く棚卸できます。
CPUでは、利用率はCPU稼働%、飽和はランキュー(run-queue)やスレッドのラン待ち、エラーはコンテナのスロットリングや割り込みの異常などです。
メモリでは、利用率は使用メモリ、飽和はページングや頻繁なガベージコレクション、エラーは割当失敗やOOMイベントです。
ディスクでは、利用率はデバイスのビジー時間、飽和はキュー深度や読み書き待ち時間、エラーはI/Oエラーやタイムアウトです。
ネットワークでは、利用率はスループット、飽和はドロップやキュー、レイテンシ、エラーは再送やRST、パケットロスです。
ユーザーが遅いと報告したとき、飽和シグナル(キューや待ち時間、競合)は多くの場合最も示唆に富んでいます:これらは生の利用率よりレイテンシと直接相関しやすいです。
リクエストレイテンシやエラー率のようなサービスレベル指標は影響を教えてくれます。USEは次にどこを見るべきかを教えてくれます。
実用的なループは次のとおりです:
REDメソッドはホストのグラフに飛び込む前にユーザー体験にアンカーを置くことを助けます。
REDはユーザーに影響しない面白いシステムメトリクスを追うのをやめさせます。「どのエンドポイントが、どのユーザーに対して、いつ遅いのか?」という切れ味のある問いを強制します。Durationがあるルートだけでスパイクしているのに全体のCPUが変わらないなら、既に鋭い出発点があります。
習慣として:REDをサービスと主要なエンドポイント(あるいは主要RPCメソッド)ごとに分解しておくと、広範な劣化と局所的な回帰を区別しやすくなります。
REDは痛みの場所を教えます。USEはどのリソースが原因かをテストするのに役立ちます。
例:
レイアウトを集中させます:
一貫したインシデントワークフローが欲しいなら、このセクションをUSE棚卸しと組み合わせて、"ユーザーが感じている"から"このリソースが制約だ"へ素早く移れるようにします(/blog/use-method-overview)。
パフォーマンス調査は数分で何十ものチャートと仮説に膨れ上がります。Greggのマインドセットは範囲を狭く保つことです:あなたの仕事は「データをもっと集める」ことではなく、不確実性を最速で取り除く次の質問をすることです。
ほとんどのレイテンシ問題は単一のコスト(あるいは小さなペア)に支配されます:ホットなロック、遅い依存、過負荷のディスク、特定のGCパターンなど。優先順位付けとは、まずその支配的なコストを探すことです。5箇所で5%ずつ削ってもユーザーが感じるレイテンシはあまり動きません。
実用的なテスト:「我々が見ているレイテンシ変化の大部分を説明できる可能性があるのは何か?」という視点で仮説を評価してください。仮説が小さな断片しか説明できないなら優先度は低いです。
トップダウンは「ユーザーは影響を受けているか?」に答えるときに有効です。エンドポイント(RED)から始めると、重要経路でないものを最適化するのを避けられます。
ボトムアップはホストが明らかにおかしいときに使います(USE症状):CPU飽和、暴走するメモリ圧など。ノードが張り付いているなら、エンドポイントのパーセンタイルを眺めているだけでは制約がわかりません。
アラートが来たら枝を選び、仮説を確認または否定するまでその枝に留まってください:
最初は小さな信号セットに絞り、何かが動いたときだけ掘り下げてください。チェックリストが必要なら、手順を /blog/performance-incident-workflow のようなランブックに紐づけて、各新しい指標が特定の質問に答える目的を持つようにします。
本番でのプロファイリングはライブシステムに触れるためリスクに感じられますが、議論を証拠に変える最速の方法であることが多いです。ログやダッシュボードは「何かが遅い」と教えてくれます。プロファイリングは「時間がどこに使われているか」を示します:どの関数が熱いか、どのスレッドが待っているか、インシデント中にどのコードパスが支配的か。
プロファイリングは「時間の予算」ツールです。「データベースだ」対「GCだ」のような議論の代わりに、"CPUサンプルの45%がJSONパースに費やされている"や"ほとんどのリクエストがミューテックスでブロックされている"のような証拠を得られます。それにより次のステップは1〜2の具体的な修正に絞られます。
各タイプは異なる質問に答えます。レイテンシが高くてCPUが低い場合、オンCPUのホットスポットよりもオフCPUやロック時間を疑うべきです。
多くのチームはオンデマンドから始め、運用の安全性が確認でき、再発が見られるようになってから常時収集に移行します。
本番安全なプロファイリングはコスト管理に関するものです。全イベントを追うのではなくサンプリングを用い、キャプチャ時間は短く(例:10〜30秒)、まずはカナリアでオーバーヘッドを評価してください。迷ったら低頻度サンプリングから始め、信号がノイジーなら徐々に上げます。
フレームグラフはプロファイリングウィンドウ中にどこにサンプリング時間が使われたかを視覚化します。各「ボックス」は関数(またはスタックフレーム)で、各スタックはその関数に到達するまでの呼び出し経路を示します。パターンを素早く見つけるのに優れていますが、自動的に「バグはここだ」とは言いません。
フレームグラフは通常オンCPUサンプルを表します:プログラムが実際にCPUコアで実行されていた時間です。CPUを大量に消費するコードパス、非効率なパース、過度のシリアライズ、実際にCPUを燃やしているホットスポットを浮かび上がらせます。
一方、ディスクやネットワークの待ち、スケジューラの遅延、ミューテックスでのブロックなどのオフCPU時間は直接的には示しません(これらはオフCPUプロファイリングが必要)。また、フレームグラフだけではユーザー可視レイテンシの因果を証明できません。スコープを明確にして結びつける必要があります。
最も幅の広いボックスに責任を押し付けたくなりますが、それが変更可能なホットスポットなのか、単に upstream の仕事(mallocやGC、ログ出力)で時間が消えているだけなのかを考えてください。JIT、インライン化、シンボル欠落などのコンテキストがないと、ボックスが実際の犯人でないのに犯人に見えることがあります。
フレームグラフは次のようなスコープ化された質問に対する答えとして扱ってください:どのエンドポイントか、どの時間窓か、どのホストか、何が変わったか。"before vs after"(正常 vs 劣化)のフレームグラフを同じリクエストパスで比較して、プロファイリングノイズを避けましょう。
レイテンシがスパイクすると、多くのチームはまずCPU%を見ます。それは理解できますが、しばしば誤った方向を指します。サービスが20%しかCPUを使っていなくても、スレッドが実行されていない時間が大半なら非常に遅く感じられることがあります。
CPU%は「プロセッサがどれだけ忙しいか」を答えますが、「リクエストの時間がどこに消えたか」は答えません。リクエストはスレッドが待たされている間に止まることがあります。
重要な考え方:リクエストのウォールクロック時間はオンCPU作業とオフCPUの待ち時間の両方を含みます。
オフCPU時間は多くの場合依存関係や競合の背後に隠れています:
オフCPUボトルネックに相関することが多い信号はいくつかあります:
これらは「待っている」と教えてくれますが、何を待っているかまでは示しません。
オフCPUプロファイリングは、"実行されていなかった理由"に時間を帰属させます:システムコールでブロックしている、ロック待ち、sleep、デスケジュールなど。これにより曖昧な遅延が扱えるアクション可能なカテゴリに変わります:"ミューテックスXでブロックしている"、"read()でディスクを待っている"、"上流へのconnect()で詰まっている"。待ちを名付ければ、計測し、確認し、修正できます。
パフォーマンス作業が失敗するのはよくあるパターンです:誰かが怪しい指標を見つけてそれを"問題だ"と宣言し、最適化を始めてしまう。Greggの手法は立ち止まって、システムを制限しているものを変更する前に証明するよう促します。
ボトルネックは現時点でスループットを制限しているかレイテンシを駆動しているリソースやコンポーネントです。これを緩和すればユーザーに改善が見えます。
ホットスポットは時間が費やされている場所です(例えばプロファイルに頻繁に出てくる関数)。ホットスポットは実際のボトルネックであることもあれば、遅いパスに影響を与えないただの忙しい作業であることもあります。
ノイズは意味ありげに見えるが実際には違うもの:バックグラウンドジョブ、一時的なスパイク、サンプリングアーティファクト、キャッシュ効果、ユーザー影響と相関しない"トップトーカー"などです。
まずクリーンなビフォアスナップショットを取得します:ユーザー向け症状(レイテンシやエラー率)と主要な候補指標(CPU飽和、キュー深度、ディスクI/O、ロック競合など)。次に、疑わしい原因にだけ影響するはずの制御された変更を加えます。
因果テストの例:
相関はヒントであり判決ではありません。"レイテンシが上がるとCPUも上がる"なら、CPUの利用可能度を変えるかCPU作業を減らしてレイテンシが追従するか確かめてください。
何を計測し、どの正確な変更を行い、ビフォア/アフターの結果と観測された改善を書き残してください。これにより一度の勝利が再利用可能なプレイブックになり、後で"直感"が履歴を書き換えるのを防げます。
パフォーマンスインシデントは緊急に感じられ、そこが推測が入りやすい瞬間です。軽量で再現可能なワークフローがあれば、"何かが遅い"から"何が変わったか分かる"へ無駄に振り回されずに移れます。
検出: ユーザー可視のレイテンシやエラー率でアラートを出す。CPUだけでなくp95/p99レイテンシが一定時間閾値を超えたらページングする。
トリアージ: すぐに三つの質問に答える:何が遅いか、いつ始まったか、誰が影響を受けているか?スコープ(サービス、エンドポイント、リージョン、コホート)を特定できなければ最適化の準備はできていません。
計測: ボトルネックを絞り込む証拠を集める。比較可能な短時間キャプチャ(例:60–180秒)を好むことで“悪い”と“良い”を比べられます。
修正: 一度に一つずつ変更し、同じ指標を再計測して改善を確認しプラセボを排除する。
インシデント中にみんなが使う共有ダッシュボードを用意してください。退屈で一貫性のあるものにします:
目的はすべてをグラフ化することではなく、最初の事実到達時間を短くすることです。
最も重要なエンドポイント(チェックアウト、ログイン、検索など)に計測を集中させ、各エンドポイントについて期待されるp95、最大許容エラー率、主要依存(DB、キャッシュ、サードパーティ)を合意します。
次のアウトページの前にキャプチャキットを合意しておいてください:
/runbooks/latency のような短いランブックに、誰がキャプチャを実行できるか、成果物をどこに保存するかを含めて記載してください。
Greggの方法論は本質的に制御された変更と迅速な検証についてです。もしチームがKoder.ai(ウェブ、バックエンド、モバイルアプリの生成と反復を支援するチャット駆動プラットフォーム)でサービスを作るなら、次の2つの機能がその考え方に合致します:
インシデント中に新しいコードを生成していない場合でも、小さな差分、計測可能な結果、迅速な可逆性といった習慣はGreggが推奨するものと同じです。
午前10:15、APIのp99が通常の約120msからピークトラフィック時に約900msに上昇しました。エラー率は横ばいですが顧客は"遅い"と報告しています。
サービスファーストで始めます:Rate, Errors, Duration。
Durationをエンドポイントでスライスすると、1つのルートがp99を支配していることがわかります:POST /checkout。Rateは2倍に上がり、エラーは通常、しかしConcurrencyが上がるとDurationが急上昇する。これはキューイングや競合を示唆します。単純な故障ではありません。
次に、レイテンシが計算時間か待ち時間かを確認します:アプリケーションの"ハンドラ時間"と総リクエスト時間(あるいはトレースがあれば上流/下流スパン)を比較してください。ハンドラ時間は短く、総時間が長い—リクエストが待たされていることがわかります。
リソースの棚卸:CPU、メモリ、ディスク、ネットワークの利用率、飽和、エラーを確認します。
CPU利用率は約35%に過ぎませんが、CPUのrun queueとコンテキストスイッチが増えています。ディスクとネットワークは安定しています。この不一致(低いCPU%だが待ちが多い)は典型的なヒントです:スレッドはCPUを燃やしているのではなく、ブロックされています。
スパイク中にオフCPUプロファイルを取得すると、共有の"promotion validation"キャッシュ周りのミューテックスに多くの時間が費やされていることが判明しました。
グローバルロックをキー毎のロック(あるいはロックフリーな読み取り経路)に置き換えてデプロイすると、Rateが高いままでもp99が基準に戻りました。
事後チェックリスト: