問題と背景
Go 1.25 では runtime/trace.FlightRecorder が追加されました。これにより、メモリ上に直近の実行トレースウィンドウが継続的に保持され、問題が検出された際にスナップショットを取得できるようになります。これは、症状が発生した後にフルプロファイルを開始しても手遅れになるような、長時間稼働サービスにおける稀なイベントを対象としています。
サービスにはレイテンシトリガー、制限された診断予算、トレースファイル用オブジェクトストレージがあると仮定します。設計においては、無制限なメモリ消費、スナップショットの重複、機密データの漏洩、インシデント処理経路の遅延を回避する必要があります。
面接官が評価するポイント
面接官は正確なライフサイクルを重視します:レコーダーの作成、1回限りの起動、制限付き WriteTo のトリガー、シャットダウン時の停止です。優れた回答では、レコーダーが単一であることの制約、シングルライターによるスナップショット動作、保持期間(age)とサイズの構成、サンプリング、マスキング(redaction)、バックプレッシャーについて議論されます。
一般的な回答では「レイテンシが急上昇したときにトレーシングを有効にする」と答えます。優れた回答では、なぜローリングウィンドウがすでに実行されている必要があるのか、そしてトリガーによってスナップショットのサンダリングハード(thundering herd)が発生するのをどのように防ぐかを説明します。
最初に確認すべき質問
- どのようなレイテンシやエラーのシグナルがスナップショットをトリガーし、そのノイズレベルはどの程度か?
- 一度に何台のインスタンスがトリガーされる可能性があり、フリート全体のキャプチャ予算はあるか?
- メモリ予算とインシデントのレイテンシに適合するウィンドウの保持期間とバイトサイズはどれくらいか?
- トレースファイルにリクエストデータ、認証情報、テナント識別子が含まれる可能性があるか?
- スナップショットはどこにアップロード、保持、暗号化、アクセス監査されるか?
シグナルにノイズが多い場合は、キャプチャ前にサンプリングとクールダウンを追加します。サービスがトレース内容を保護できない場合は、レコーダーを制限するか、より安全な診断シグナルを使用します。
30秒での回答例
「プロセスごとに1つの FlightRecorder を期間とメモリを制限した構成で実行し、サンプリングおよびデバウンスされた SLO 違反時のみスナップショットをトリガーします。単一のライターが WriteTo をシリアライズし、リクエストパスは処理をキューに追加して迅速に復帰すべきです。トレースファイルのマスキングまたは暗号化、フリート全体でのキャプチャ数の上限設定、レコーダーエラーやアップロードレイテンシの監視を行い、シャットダウン時にはレコーダーをクリーンに停止します。」
ステップごとの設計
- 作成と1回限りの起動。 制限付きウィンドウで
FlightRecorderConfigを構築し、Startを呼び出します。キャプチャが動作していると暗黙に仮定するのではなく、起動失敗をメトリクスとして公開します。 - ウィンドウの選定。 予想される診断間隔とメモリ予算から、最小保持期間とバッファサイズを選択します。ウィンドウを大きくするとコンテキストは向上しますが、メモリとアップロードコストが増加します。
- トリガーの設計。 サンプリング、クールダウン、プロセスごとおよびフリート全体のクォータを備えたレイテンシ、エラー、またはヘルスシグナルを使用します。すべてのリクエストが
WriteToを呼び出すことがないようにします。 - スナップショットのシリアライズ。
WriteToは同時に1つのライターのみを許可します。キャプチャジョブを制限付きチャネルに配置し、重複を破棄または合流(coalesce)させ、ホットパスを非ブロッキングに保ちます。 - データの保護。 トレースを機密性の高い運用データとして扱います。転送中および保存時に暗号化し、保持期間とアクセスを制限し、ログに生のペイロードをコピーせずにインシデントのメタデータを付与します。
- 安全な運用。 キャプチャの成功、バイト数、所要時間、破棄されたトリガー、アップロード失敗、レコーダーの状態を記録します。グレースフルシャットダウン時に停止し、実行中の書き込みが完了することを確認します。
代替手段としては、制御されたテスト用の従来の開始/停止トレーシング、CPU またはヒープの調査用プロファイル、ビジネスコンテキスト用の構造化リクエストログなどがあります。フライトレコーダーは、症状が稀であり、有用なエビデンスが検出前に存在する場合に最も威力を発揮します。
回答の具体例
「メモリ制限に応じた5秒の制限付きウィンドウを持つレコーダーをプロセスごとに1つ起動します。サンプリングされた p99 違反により、インスタンスごとに1分間に1回のキャプチャをキューに追加できるようにし、フリートのクォータによってインシデントがオブジェクトストレージを圧迫するのを防ぎます。ワーカーは WriteTo をシリアルに呼び出し、トレースを暗号化して非同期にアップロードします。リクエストパスはキャプチャが要求されたことのみを記録します。キャプチャエラー、破棄されたトリガー、アップロードレイテンシ、バイト数を公開し、並行書き込みが完了するようにレコーダーをグレースフルに停止します。」
よくある間違い
- 間違い: アラートが発生した後にトレーシングを開始する → 失敗する理由: それ以前のエビデンスが失われている → 修正方法: 制限付きローリングウィンドウを常にアクティブにしておく。
- 間違い: すべてのリクエストでスナップショットを取得させる → 失敗する理由: 並行書き込みとストレージへの負荷集中がサービスを過負荷にする → 修正方法: サンプリング、デバウンスを行い、1つのライターにキューイングする。
- 間違い: トレースの機密性を無視する → 失敗する理由: 運用上のエビデンスによってテナントデータが漏洩する可能性がある → 修正方法: 暗号化、アクセス制限、マスキングを行い、短期間のみ保持する。
- 間違い:
StartやWriteToのエラーは発生しないとみなす → 失敗する理由: インシデント発生時にキャプチャがサイレントに失敗する → 修正方法: 明示的なメトリクスとフォールバック動作を実装する。
フォローアップ質問と回答
2つの goroutine が同時に WriteTo を呼び出した場合はどうなりますか?
単一のキャプチャワーカーを介して呼び出しをシリアライズします。API は進行中の並行書き込みに対してエラーを返すため、呼び出し元はタイトなループでリトライするのではなく、トリガーを合流させる必要があります。
バッファサイズはどのように決定しますか?
根本原因から検出までの時間から検討を始め、プロセスごとおよびフリート全体のメモリを制限します。代表的なトレースボリュームで検証し、欠落したコンテキストを観察します。
トレースのスナップショットがリクエストパスをブロックすることはありますか?
低速なネットワーク送信先へ同期的に書き込まないでください。制限付きジョブをキューに入れ、制御されたバッファまたはファイルにスナップショットを取得し、タイムアウトと破棄ポリシーを設けて非同期にアップロードします。
シャットダウン中は何が起きますか?
新規キャプチャの受け入れを停止し、Stop を呼び出し、実行中の書き込みの終了を待ち、アップロード経路を閉じます。最終スナップショットが完了したか、意図的に破棄されたかを記録します。