ようこそ
ようこそ
ウェブスケールのフリートには多数のマシンが含まれています。ある時点で、一部のマシンは正常、一部のマシンは起動中、一部のマシンはドレイン中、そして一部のマシンは静かに故障している可能性があります。フリートがこの状況に耐えられるのは、すべてのマシンが要求に応じて2つの単純な質問に答えることができるからです:
- /health — 現在、実際のリクエストを処理できますか?
- /version — どのコードを実行していますか?
監視ツールがスクレイプするための、カウンターとゲージを公開するメトリクスエンドポイント(一般的には /metrics)も含まれます。
このレッスンでは、これらのエンドポイントが実際の状態を正確に反映するように設計する方法、プロキシ層における4つのゴールデンシグナルの意味、そして観測データがキャパシティ決定をどのように駆動するかを学びます。
このレッスンを終えるまでに、以下のことができるようになります:
- プロセスの生存性だけでなく、実際のパスの障害を検出できる /health エンドポイントの設計
- デプロイが正常に適用されたことを検証できる /version エンドポイントの設計
- プロキシ層における4つのゴールデンシグナル(レイテンシ、トラフィック、エラー、飽和度)の適用
- 観測されたサージ(急増)メトリクスをキャパシティ決定に結びつける:スケールアップのタイミング、ドレイン(排空)のタイミング、ページング(アラート通知)のタイミング
- 「どの程度気にすべきか?」という運用規律の背後にある、SLO(サービスレベル目標)とエラーバジェット燃焼率について論理的に考える
2種類のヘルスチェック
ライブネスとレディネス
ライブネス(Liveness): プロセスは生存しているか? オーケストレーター(Kubernetes、systemdなど)がプロセスの再起動を判断するために使用されます。
レディネス(Readiness): プロセスは現在、実際のトラフィックを処理できる状態か? ロードバランサーがリクエストを送信するかどうかを判断するために使用されます。
これらは異なる質問です。データベースに接続できないプロセスは、生存はしているがレディではない状態です。起動中のプロセスも、生存はしているがまだレディではない状態です。
浅いヘルスチェックと深いヘルスチェック
浅い(Shallow): HTTPハンドラーが実行される場合、{"status": "ok"} を返します。非常にシンプルで、プロセスの停止のみを検出できます。
深い(Deep): 実際のリクエストパスを実際に検証します。データベース接続プールから接続が返却可能か、キャッシュに到達可能か、下流の依存性が応答するかを確認します。浅いチェックでは検出できない機能的な障害を検出できます。
トレードオフ: 深いチェックはコストが高くなります(各チェックは本質的に合成リクエストです)& 連鎖的な障害を引き起こす可能性があります(すべてのレプリカのヘルスチェックがデータベースを叩く場合、遅いデータベースはすべてのレプリカを非健全にし、それらをローテーションから除外し、結果としてすべての容量を失うことにつながります)。
ベストプラクティス: 生存確認(liveness)用の浅いチェック(高速、低コスト、外部依存なし)& 準備完了(readiness)用のより深いチェック(結果をキャッシュし、下流への過剰な負荷を避けるためにスロットリングする)。
バージョンエンドポイント
/version は git コミット、ビルド時間、& サービス名を返します。デプロイ後、curl https://service.example.com/version を実行し、返されたコミットがプッシュしたものと一致することを確認します。一致しない場合、デプロイはサイレントに失敗しています。
/version がなければ、古いデプロイが成功したように見せかけ、数時間隠蔽される可能性があります。
最小限のレスポンス形式: {"service": "my-api", "git_commit": "abc1234", "build_time": "2026-05-19T10:00:00Z"}。
レイテンシ、トラフィック、エラー、飽和度
4つの数値が運用の大部分をカバーする
Google SREブックより。すべてのサービスティアで測定する4つのシグナルです。これら4つを適切に計装(インストルメンテーション)すれば、ユーザーが気づく前にほとんどの本番環境の問題を捕捉できます。
レイテンシ: リクエストにどれくらいの時間がかかるか?平均値だけでなく、分布を報告すること。p99(99パーセンタイルのレイテンシ)は平均値よりも重要であり、それはテールレイテンシがユーザーに「遅い」と感じられる部分だからです。平均50 msでp99が5,000 msのサービスには、ほとんどのユーザーが気づかないが、最も影響を受ける1%のユーザーには確実に影響を与える実際の問題があります。
トラフィック: 1秒あたりのリクエスト数はいくつか?総リクエスト数、エンドポイント別、ステータスコード別、リージョン別。ベースラインを把握し、異常時にアラートを出す(急激な減少 = 入口の問題、急激な増加 = スパイクまたは攻撃)。
エラー: 失敗したリクエストの割合。4xx(クライアントエラー、あなたの責任ではない)と5xx(サーバーエラー、あなたの責任)を区別すること。トラフィックに対する割合としてエラー率を追跡し、絶対数ではなく、負荷レベルを問わずアラートが機能するようにすること。
飽和度: システムがどれほど満杯か?CPU使用率、メモリ、コネクションプールの深さ、キューの長さ。先行指標です。レイテンシやエラーが悪化する前に飽和度は上昇します。90%の飽和度にあるティアは、キューの崩壊まで悪い1分間しか離れていません。
プロキシティアに特化した場合
各シグナルはエッジ層で点灯します:
- プロキシでのレイテンシ: TLSハンドシェイクの所要時間、アップストリーム接続時間、リクエスト-レスポンスの総時間。パスの異なる部分に存在するため、個別に測定します。
- プロキシでのトラフィック: 総リクエスト/秒、バックエンドごとの分布(ホットバックエンドはロードバランサーの偏りを示す)、ステータスコード別の内訳。
- プロキシでのエラー: クライアント(ユーザーが不正なエンドポイントにアクセスした場合)からの4xx、バックエンド(サービスが失敗した場合)からの5xx、プロキシ内部のエラー(502 = バックエンドに到達できない、504 = バックエンドのタイムアウト)。
- プロキシでの飽和: TLSセッション数、アップストリーム接続プールの深さ、プロキシ自体のCPU使用率(TLS終端はCPU負荷が高い)。
プロのヒント: バックエンドのレイテンシが低い状態で502が急増した場合、バックエンドが応答する前に接続を切断していることを意味します(接続リセット、クラッシュ、OOM)。504が増加している場合は、バックエンドが遅いがまだ応答していることを意味します。エラーコードを読み解くことで、障害が発生している場所が分かります。
シグナルを読み解く
ダッシュボードには、過去10分間の以下のデータが表示されています:
- トラフィック: 約800 req/sでほぼ横ばい(急増なし)
- レイテンシ: p50は40msで安定、p99は5分間で200msから2,500msに上昇しており、まだ上昇中
- エラー: 4xx レートは 0.3% で安定(通常の背景ノイズレベル);5xx レートは 0.1% から 1.2% に上昇(主に 504 Gateway Timeout)
- 飽和度: バックエンドの CPU 使用率は同じ 5 分間で 45% から 78% に上昇;プロキシの CPU 使用率は 30% で安定
スケールアップ、ドレイン、ページングのタイミング
容量に関する判断にはトリガーが必要
メトリクスを観察することは容易です。それに基づいていつ行動すべきかを知ることが、真の規律です。
スケールアップのタイミング: 飽和度が持続的な閾値を超えた場合(例:バックエンドCPUが5分間70%超)、またはキューの深さが目標値を超えた場合、またはレイテンシのp99がSLOを超えた場合。トリガーは、システムが壊れる前に、壊れる瞬間に発火すべきです。
レプリカをドレインするタイミング: ピア(他のレプリカ)が正常な状態で、特定のレプリカが一貫して低速またはエラーを返している場合(1つのレプリカが過負荷状態にあることは、アプリケーションの問題ではなくホストレベルの問題であることが多い)、または新しいバージョンをロールアウトする場合、またはレプリカを適切に引退する場合。
人間にページング(緊急連絡)するタイミング: エラーバジェットが持続できる速度を超えてSLOが消費されている場合、または飽和度トリガーが発火したがオートスケーリングで吸収されなかった場合、またはカスケードパターン(エラー率とリトライ率の両方が上昇)が現れた場合。
ページングしないタイミング: 単発の不良分が自然に解決した場合、またはバックグラウンドのバッチジョブが予期された周期的な変動を引き起こした場合、またはノイズが閾値を超えた場合(この場合はシステムではなく閾値の設定が誤っている)。
SLOとエラーバジェット燃焼
SLO(サービスレベル目標)は許容されるパフォーマンスを定義します。「28日間のウィンドウで成功率 >= 99.9%」。その補数(0.1%)がエラーバジェットです。
燃焼率(Burn rate):エラーバジェットを消費する速度です。1時間でバジェットの10%を消費した場合、その速度は持続可能な速度の240倍です(1時間は28日間のウィンドウの1/672であり、そのウィンドウで10%を消費することは、許容される100%に対して、フルウィンドウで6720%(10% × 672)を消費することを意味します)。
マルチウィンドウ燃焼率アラート:短いウィンドウ(5分間、14.4倍の速度)と長いウィンドウ(1時間、6倍の速度)の両方で、持続可能な速度を超えて燃焼している場合にページング(緊急通知)を発行します。これにより、急速な障害と緩やかな性能低下の両方を検出できます。
容量管理における重要性:99.9%のSLOで1%の余裕があるサービスは、軽微な変動を吸収できます。一方、99.93%(SLOをわずかに満たしている状態)のサービスは、悪い日が続けばすぐにSLO違反に陥ります。容量の決定では、SLOを満たす最小限ではなく、快適なSLOの余裕を目標とすべきです。
観察下での容量決定
あなたのサービスには、28日間で99.9%のリクエストが成功するというSLOがあります。過去1時間のモニタリングからの現在の状態は以下の通りです:
- 成功率:99.5%(30分間持続)
- バックエンドCPU: フリート全体で平均82%(目標70%)
- p99レイテンシ: 800 ms(SLO目標: 500 ms未満)
- トラフィック: 1,400 req/s、ベースラインの1,000 req/sから増加(通常比+40%、トレンドは依然として上昇中)
- オートスケーリング: CPUが5分間継続して80%を超えるとレプリカを追加するように設定済み。現在、約90秒後に3つのレプリカを追加するスケーリングアップの最中
ローンチ時のオブザーバビリティ計画を設計する
統合
これにより、実際の障害を検出できる /health、デプロイを検証できる /version、プロキシ層での4つのゴールデンシグナルのダッシュボード、およびSLOバーンレートに連動したキャパシティトリガーを設計できるようになります。
これら4つをすべて適用してください。
あなたのチームは search.example.com(障害モードのレッスンで扱った検索サービス)をローンチします。チームは、ユーザーが気づく前に問題を検出できるオブザーバビリティを構築し、明確なページング(当番対応)または非ページングの意思決定マトリクスを確立することを求めています。SLO:28日間のウィンドウにおいて、成功リクエスト率 99.9%、p99 レイテンシ < 300 ms。
コースの締めくくり
コースの締めくくり
5つのレッスンをすべて完了しました:
- プロキシとオリジン: ほぼすべてのパブリックなWebサービスが使用するエッジレイヤーの構成
- ステートレスな水平スケーリング: ステートレスなレイヤーがなぜ安価に増殖できるのか、そしてどのようにサイズを決定するか
- イングレスとエグレスの分離: なぜ1台のボックスが2台になるのか、そしてそれを強制する障害モード
- 障害モードと影響範囲: SPOF(単一障害点)、カスケード障害、ポストモーテム、非責任意向きのアクションアイテム
- オブザーバビリティとキャパシティ(本講義): ユーザーが問題に気づく前に問題を表面化させるために何を測定すべきか
全体を貫くテーマ: ウェブスケールの分散システムは魔法ではありません。それは、リバースプロキシ、ステートレスレプリカ、イングレス/エグレスの分離、バルクヘッドとサーキットブレーカー、4つのゴールデンシグナルといった、少数のパターンを思慮深く組み合わせることで構成されています。これらのパターンを認識できるようになれば、あらゆる本番環境のアーキテクチャでそれらを見出すことができます。
関連講義: 5つの「*の幾何学」講義では、同じ内容をグラフ理論と幾何学として再構成しています。どちらの順序でも学習に適しています。
お疲れさまでした。