代表的な面接トピック

システム設計面接:分散トレーシングプラットフォームをどのように設計しますか?

システム設計難しい
Offer.cc 編集チーム公開日 更新日

質問

毎秒500,000件の新規ルートワークフローと、ワークフローあたり平均15スパンを処理するマルチテナント分散トレーシングプラットフォームを設計してください。プラットフォームは、相互運用可能なコンテキストを伝播し、アプリケーションリクエストを遅延させることなくスパンを取り込み、不完全または順不同なトレースを再構築し、正確なトレースID検索およびフィルタリング検索をサポートし、制限されたストレージバジェット内で有用なトレースを保持する必要があります。保持されたトレースはp99で30秒以内に検索可能になり、正確なトレースID検索はp99で2秒以内に完了し、リージョン内の1つのアベイラビリティゾーン障害が発生しても計装が中断されてはなりません。API、スパンモデル、伝播境界、ヘッドサンプリングとテールサンプリング、ルーティング、ストレージとインデックス、キャパシティ、マルチテナンシー、デグラデーション、および検証について説明してください。

プロンプトとスコープ

バックエンドチームおよび信頼性エンジニアリングチームが、サービスをまたぐ単一のリクエストや非同期ワークフローを追跡するために使用する、マルチテナント分散トレーシングプラットフォームを設計します。面接での前提条件は、毎秒500,000件の新規ルートワークフロー、ワークフローあたり平均15スパン、ストレージ圧縮前でエンコードされたスパン1件あたり700バイトです。保持されたトレースはp99で30秒以内に検索可能になる必要があります。テナントおよびトレースIDによる完全一致検索はp99で2秒以内に完了し、サービス、オペレーション、エラー、所要時間、時間枠による一般的な検索はp95で3秒以内に完了する必要があります。計装処理が中央プラットフォームを同期的に待機してはならず、1つのアベイラビリティゾーンを失ってもアプリケーションからのテレメトリ送信が停止してはなりません。

プラットフォームは、スパンの作成または受信、サポートされているトランスポートを介したW3Cトレースコンテキストの伝播、遅延や順不同で到着するスパンの組み立て、明示的なバジェットに基づくトレース全体のサンプリング、トレース詳細の保存、および保持されたトレースから導出される依存関係グラフのサポートを行います。すべての言語のSDK開発、完全なAPM UI、ログストレージ、メトリクスストレージ、異常検知の構築はスコープ外です。ログやメトリクスがトレースIDやエグゼンプラ(exemplar)を保持することはありますが、それらは別個のシステムとして扱われます。

2026年の3つの独立した面接準備ページでは、分散トレーシングがスパン、コンテキスト伝播、トレース組み立て、サンプリング、クエリストレージを網羅するシステム設計課題として提示されています。これは特定の企業への帰属を証明することなく現在の代表性を確立するものであるため、本記事では特定の企業への言及は行いません。技術モデルは、W3C Trace Context勧告、OpenTelemetry仕様およびCollector実装、GoogleのDapper論文に基づいています。

面接官が評価しているポイント

第1のシグナルは、候補者がプロセス境界を越えて因果関係を保持できるかどうかです。trace_idだけでは不十分です。各操作にはspan_id、親関係または明示的なリンク、タイミング、ステータス、リソース識別情報、および適切に制限された属性が必要です。W3Cフォーマットは相互運用可能なtraceparenttracestateにおけるオプションのベンダー状態を定義していますが、信頼されていない受信トレースIDを認可クレデンシャルにするわけではありません。優れた回答は、受信コンテキストを検証し、取り込み時にテナントを分離し、信頼境界での動作を明確に定義します。

第2のシグナルは、誠実なサンプリングモデルです。ヘッドサンプリングはトレース全体が判明する前に決定を下すため、SDK、ネットワーク、および取り込みの負荷を削減できます。ただし、後続のすべてのエラーを保持することを保証することはできません。テールサンプリングはほとんどのスパンを確認した後にトレースを選択できますが、まずそれらのスパンを受信して保持しなければなりません。これにより下流のストレージコストは削減されますが、上流の収集コストは削減されません。2%のヘッドサンプラーがすでにトレースを破棄していた場合、後続のテールサンプラーがそのエラーのスパンを復元することは不可能です。

第3のシグナルは、汎用的なイベントパイプラインではなく、トレースの組み立てに焦点を当てているかです。スパンは重複、遅延、順不同で到着します。また、非同期のファンアウトやバッチ処理は、綺麗なツリー構造ではなく有向非巡回グラフ(DAG)を形成することがあります。テールサンプラーには、1つのトレースのすべてのスパンを同一の決定オーナーにルーティングする仕組み、制限された完了ルール、メモリ保護、および遅延スパンに対する明示的な動作が必要です。このステートフルな境界が、設計が有用な証拠を生み出すか、それとも潜在的なサンプリングバイアスを生み出すかを左右します。

最後のシグナルは運用性です。優れた回答は、生ボリュームと保持ボリュームを定量化し、任意の属性インデックスを制限し、ノイズの多いテナントを分離し、伝播の欠落やドロップされたスパンを測定し、テレメトリのパスがアプリケーションの依存関係にならないようにします。「スパンをデータベースに書き込む」だけで終わる図は、コスト、正確性、および障害に関する疑問を未解決のまま残してしまいます。

回答前に明確にすべき質問

  • どのワークフローがテールでの決定を必要としますか? 完全なテールサンプリングには、候補となるすべてのスパンを中央で受信する必要があります。この設計では、通常トラフィックに対して送信元でのヘッドサンプリングを使用し、制御された一連のクリティカルなルートを100%でテールプールに送信します。すべてのルートでエラーを認識した保持が必要な場合、生のストリーム全体が中央のネットワークおよびステートバジェットに収まらなければなりません。
  • 「完全なトレース」とは何を意味しますか? キューや分離された作業をまたぐ普遍的な終了マーカーは存在しません。同期リクエストの場合、終了したルートスパンに猶予時間を加えたものが有用です。長時間実行されるワークフローには、より長い保持ポリシーまたは明示的なワークフロー完了通知が必要です。プラットフォームは確実性を主張するのではなく、incompleteフラグを公開する必要があります。
  • どの検索が契約上の要件ですか? 完全一致のトレースID検索、およびサービス、オペレーション、ステータス、所要時間バケット、時間に関する制限されたフィルタがスコープ内です。すべての属性に対する任意の全文検索述語はインデックスコストを何倍にも増大させ、高カーディナリティの乱用を引き起こすため、許可リストにない属性はトレース取得後にのみ利用可能とします。
  • データはどのくらいの期間保持されますか? 前提とするポリシーは、7日間のインデックス付きホットデータと、さらに23日間の圧縮オブジェクトデータです。ホットデータの保持期間を長くすると、ストレージとインデックスのサイジングが変わります。また、法的な削除ルールによって、オブジェクトキーと暗号化ドメインをテナント固有にする必要があるかどうかも決まります。
  • テナント間のクロスドメイントレースは許可されますか? デフォルトでは許可されません。ゲートウェイは認証されたクレデンシャルをテナントにバインドし、スパン内で提供されたテナントフィールドを上書きします。承認されたクロスドメインワークフローでは明示的なリンクまたは個別に認可された相関関係を使用し、クライアントが選択したテナント識別子は決して使用しません。
  • 非同期の因果関係はどのように表現すべきですか? 単一の親は1つの因果的前任者に有効です。バッチコンシューマやファンインは複数のプロデューサに依存する可能性があるため、スパンリンクが必要です。1つの親を強制すると情報が失われ、複数の親の下に1つのスパンを複製するとトレースの会計処理が破損します。
  • 過負荷時にアプリケーションは何を損失しても許容されますか? ビジネストラフィックは継続しなければなりません。制限されたローカルキューは、メモリおよびディスクバジェットを使い果たした後にテレメトリをドロップすることがありますが、その損失はサービス、テナント、理由、サンプリングクラスごとにカウントされます。テレメトリの損失ゼロが求められる場合、トレーシングはビジネスパスの依存関係となり、可用性の契約を変更する必要があります。

30秒の回答フレームワーク

「コンテキスト伝播、収集、トレース決定、およびクエリストレージを分離します。計装されたライブラリがスパンを作成し、検証済みのW3Cコンテキストを伝播します。ローカルエージェントがそれらを非同期にバッチ処理し、制限されたスプールを使用するため、中央プラットフォームがリクエストパスをブロックすることはありません。リージョンゲートウェイがテナントを認証し、スキーマとクォータを適用し、トレースIDでパーティション分割された高耐久ストリームにスパンを追加します。

通常のルートでは一貫したヘッドサンプリングを使用して上流のコストを削減します。クリティカルなルートは完全なテールプールに入ります。1つのトレースのすべてのスパンが1つのアセンブラに到達し、アセンブラはルートスパンの終了と猶予期間を待機し、エラー、レイテンシ、ベースラインのバジェットを適用して、トレースが不完全かどうかを記録します。保持されたトレースは正規の詳細情報としてオブジェクトストアに送られ、トレースIDおよび制限されたフィルタ用に許可リストに基づくホットインデックスに送られます。サンプリング前の状態と保持ストレージの両方をサイジングし、優先度の低い通常トレースから順にドロップしてデグラデーションを行い、カナリートレースを使用して伝播、遅延スパン、偏ったサンプリング、テナント分離、およびゾーン復旧を検証します。」

ステップごとの詳細解説

ステップ1:スパンの契約とクエリAPIを定義する。

スパンレコードには少なくとも以下が含まれます。

text
Span {
  tenant_id, trace_id, span_id, parent_span_id?, links[],
  service, operation, kind, start_time, end_time, status,
  resource_attributes, span_attributes, events[],
  observed_at, schema_version, trace_flags, tracestate?
}

ゲートウェイは認証情報からtenant_idを導出します。識別子の長さと形式を検証し、サイズ超過のレコードを拒否し、承認されたセマンティックフィールドを正規化し、属性数、値の長さ、イベント数、リンク数、総バイト数を制限します。イベント時間とobserved_atの両方を保存します。サービス側のクロックはタイムラインの描画に役立ち、コレクター側の時間は遅延やクロックスキューの問題を浮き彫りにします。ホスト間の順序付けには依然として実時間(ウォールクロック)と因果関係のエッジが必要ですが、SDKは単調増加クロック(モノトニッククロック)を使用してローカルスパンの所要時間を測定する必要があります。

主なクエリ契約は以下のとおりです。

text
GetTrace(tenant_id, trace_id)
SearchTraces(tenant_id, start, end, service?, operation?, status?,
             min_duration?, max_duration?, cursor?, limit?)

GetTraceはスパン、リンク、サンプリングポリシーとバージョン、first_observed_atlast_observed_at、および完全性の警告を返します。SearchTracesは制限された時間範囲を必要とし、無制限のオフセットではなくカーソルを返します。詳細の取得とセカンダリ検索は異なるアクセスパスです。1つのワイドなトレースレコードをすべてのセカンダリインデックスに複製するべきではありません。

ステップ2:コンテキストを信頼関係に変換することなく伝播させる。

HTTPの場合、SDKはバージョン、トレースID、親ID、フラグを保持するW3C traceparentを抽出し、注入します。tracestateはオプションのベンダー固有状態を保持します。メッセージプロデューサは、メッセージのメタデータに同じ伝播フィールドを設定します。レシーバは、トレースに参加する前にフォーマットを検証します。無効なコンテキストの場合は新しいトレースを開始し、既存のキー空間を汚染するのではなく伝播エラーカウンタをインクリメントします。

インターネットに面した境界やテナント間の境界では、サービスは意図的に新しいトレースを開始し、承認された上流コンテキストへのリンクを付与できます。これにより、外部の呼び出し元に内部の親やサンプリング制御を選択させることなく、相関関係を維持できます。Baggageは独立した伝播型Key-Valueメカニズムです。下流のすべてのホップにファンアウトするため、許可リストに登録され、サイズが制限され、シークレットや個人データが除外されている必要があります。

まず、一般的なHTTP、RPC、データベース、キューのライブラリを自動計装します。Dapperが示したように、共通ライブラリの計装は、少ないアプリケーション開発工数でカバレッジを向上させます。カスタムスパンはビジネス境界において引き続き有用ですが、プラットフォームは期待されるサーバーまたはクライアントスパンが不足しているサービスやルートを測定します。トレースの品質は、計装と保持されたサンプルの完全性に依存します。

ステップ3:収集処理をアプリケーションのリクエストパスから外す。

終了したスパンはプロセス内の制限付きバッファに入り、圧縮されたバッチとしてノードエージェントまたはサイドカーにフラッシュされます。エージェントは、短時間のコレクター停止に対応するための制限付きディスクスプール、ジッター付き指数バックオフによるリトライ、および優先度ごとのキューを備えています。アプリケーションがレスポンスを完了する前に、中央からの確認応答(ACK)を同期的に待つことは決してありません。ローカルバジェットを使い果たすと、まず優先度の低い通常のテレメトリをドロップし、失われた内容を正確に説明するカウンタをエクスポートします。

リージョンのステートレスゲートウェイはエージェントを認証し、テナントをバインドし、バイトおよびスパンのクォータを適用し、スキーマを検証し、受け入れたバッチを複製された高耐久ストリームに追加します。確認応答は、リージョンストリームがバッチを高耐久に受け入れたことを意味し、検索機能にすでに含まれていることを意味するわけではありません。コンシューマは(tenant_id, trace_id, span_id)とレコードバージョンによって冪等性を保ちます。重複配信された場合は観測メタデータが更新されますが、スパンが重複することはありません。

ストリームは(tenant_id, trace_id)の安定ハッシュによってパーティション分割されます。これにより、グローバルなスパン順序を必要とすることなく、1つのトレースに順序付けられた決定オーナーが与えられます。大規模なテールサンプリングでは、第1のコレクターレイヤーがトレースIDによって第2のステートフルレイヤーに負荷分散できます。OpenTelemetry Collectorも同じ不変条件を文書化しています。つまり、1つのトレースのすべてのスパンが同一のテールサンプリングインスタンスに到達しなければなりません。

ステップ4:すべてのキャパシティ境界を再計算可能にする。

サンプリング前のワークロードは以下を生成します。

text
500,000 workflows/s × 15 spans/workflow = 7,500,000 spans/s
7,500,000 spans/s × 700 bytes/span = 5.25 GB/s
5.25 GB/s × 86,400 s = 453.6 TB/day raw

これらはワークロードの前提条件であり、測定された圧縮率の主張ではありません。すべての生スパンを中央のテールサンプラーに送信するプラットフォームは、レプリケーション、プロトコルオーバーヘッド、リトライ、スキュー、およびフェイルオーバー用のヘッドルームを考慮する前に、5.25 GB/sの取り込みパスをプロビジョニングする必要があります。

通常のルートがスパンの90%を生成し、2%の一貫したヘッドサンプリングを使用すると仮定します。クリティカルなルートは10%を生成し、100%でテールプールに入ります。

text
ordinary: 7.5M × 90% × 2% = 135,000 spans/s
tail pool input: 7.5M × 10% = 750,000 spans/s
collector input: 885,000 spans/s × 700 bytes = 619.5 MB/s

テールポリシーが候補スパンの平均10%を保持する場合、ホットストレージは135,000 + 75,000 = 210,000 spans/s、すなわち圧縮、レプリケーション、インデックス、オブジェクトメタデータの前で147 MB/sおよび12.7008 TB/日を受信します。生データ換算で7日間のホットデータは88.9056 TBになります。本番の属性分布を用いたベンチマークによって圧縮率とノード数が決定されます。ここでの計算は下限を確立し、どのサンプリング境界がどのコストを支払うかを示すためのものです。

ステップ5:テールサンプリングを決定的なステートフルボトルネックとして扱う。

アセンブラは、テナントとトレースIDをキーとして部分的な状態を保存します。これには、一意のスパン、最も早い開始時刻、最も遅い終了時刻、ルート終了状態、エラー状態、現在の所要時間、バイト数、最終到着時刻が含まれます。同期トレースは、ルートが終了し猶予期間が経過した後に決定の対象となります。また、最大経過時間、スパン数、またはバイト数に達した際にも強制的に決定されます。長時間実行されるワークフローには別のポリシーを使用します。そうしないと、1つのトレースがメモリを無期限に占有する可能性があります。

決定順序としては、明示的なクリティカルフロー、エラー、高レイテンシトレース用のキャパシティを予約し、その後、サービスごとおよびテナントごとのバジェット内で一貫した確率的ベースラインを使用します。「すべてのエラーを保持する」というグローバルルールは、エラー率が100%に近づく可能性があるインシデント発生時には制限されたポリシーとは言えません。トークンバケットと厳格なバイト上限によって各クラスを制限します。バジェット枯渇に対する応答は、メモリ不足(OOM)によるクラッシュではなく、可視化されたデグラデーションポリシーの適用です。

サンプラーは遅延スパン用の決定キャッシュを記録します。保持されたトレースの遅延スパンは追加され、トレースが更新された旨がマークされます。ドロップされたトレースの遅延スパンは一貫して破棄されます。キャッシュの有効期限が切れた後に到着したスパンは孤立としてカウントされます。誤解を招くような単一スパンのトレースを作成してはなりません。保存されたすべてのトレースは、completedecision_reason、および遅延スパンカウンタを保持します。猶予期間を長くすると完全性は向上しますが、メモリ、決定レイテンシ、サンプラー障害にさらされるトレース数が増加します。

重大な落とし穴はハイブリッドパイプラインです。テールロジックは、自身に到達したトレースの中からしか選択できません。2%のヘッドサンプラーが下流でエラーが発生する前に通常トレースを破棄した場合、テールステージでそれを復元することはできません。したがって、エラーを認識した決定を確実に必要とするルートは、上流でのドロップ決定なしでテールプールに入るか、別のトリガーを使用して過去の再構築は行われないことを受け入れる必要があります。

ステップ6:正規の詳細情報を制限付きインデックスとは別に保存する。

保持されたスパンは、テナントと時間でパーティション分割された不変の圧縮オブジェクトに圧縮され、トレースのリビジョンごとにマニフェストが作成されます。トレースIDディレクトリは、(tenant_id, trace_id)をオブジェクトの場所および最新リビジョンにマッピングします。このパスは完全一致検索を処理します。最近のトレースオブジェクトはキャッシュされる場合がありますが、オブジェクトレイヤーが派生インデックスの再構築ソースとなります。

ホット検索インデックスは、トレースごとに1行のサマリーを保存します。これには、テナント、トレースID、ルートサービスおよびオペレーション、開始バケット、所要時間、ステータス、選択されたサービスセットまたはフィンガープリント、サンプリング理由、完全性、オブジェクトポインタが含まれます。許可リストに登録されたフィールドのみがセカンダリインデックスを受け取ります。任意のユーザーID、SQLテキスト、URL、Baggage値は保護された詳細情報に残されるか、秘匿化(リダクション)されます。これらをデフォルトでインデックス化すると、カーディナリティの爆発、プライバシーの漏洩、書き込み増幅が発生します。

サービス依存関係およびレイテンシのビューは、保持されたトレースに対するストリーミング集計であり、サンプリングされた推定値としてラベル付けする必要があります。確率が既知の場合、サンプリング重みによって偏りのないカウント推定をある程度サポートできますが、エラーやレイテンシに偏ったテールサンプルは、トラフィックの割合を自動的に代表するものではありません。メトリクスが依然としてフリート全体の正確なレートを取得するためのソースであり、トレースは個々の因果関係パスを説明するものです。

ステップ7:テナントを分離し、障害時の動作を定義する。

ゲートウェイは、テナントごとの秒あたりバイト数、秒あたりスパン数、同時実行中の部分トレース数、クエリ同時実行数、保持バイト数を適用します。パーティションキーにはテナント識別子が含まれ、暗号化ポリシーによって規制対象のテナントを分離でき、インデックス検索の前にクエリの認可がチェックされます。巨大なトレースや高カーディナリティの属性を持つ単一のテナントが、他のテナントのサンプラー状態を追い出してはなりません。

ゲートウェイまたはアベイラビリティゾーンに障害が発生した場合、エージェントは別のリージョンエンドポイントにリトライし、制限付きスプールを使用します。高耐久ストリームが低速な場合、アドミッションコントロールが通常のサンプリング率を下げ、ステートフルな組み立ての前に超過バイトを拒否します。アセンブラが停止した場合、ストリームはそのパーティションを再生します。チェックポイントによって復旧が高速化され、冪等なスパンキーが重複を吸収します。インデックスの停止中も正規オブジェクトは継続して保存され、インデックスのバックログが増加します。最近書き込まれたデータの完全一致クエリは、誤った「見つかりません」を返すのではなく、「受付完了、インデックス作成中」と報告する場合があります。

テールプールが過負荷になった場合は、確率的ベースラインを段階的に減らし、大きなトレースを制限し、影響を受けるルートに対して決定論的なヘッドポリシーにフォールバックします。コントロールプレーンのカナリートレースと、一定のエラー処理キャパシティは維持します。テナント、サービス、ゾーン、ポリシーごとに、受付、ドロップ、リトライ、早期退出、遅延、孤立、インデックス作成されたスパンを監視します。

ステップ8:スループットだけでなく、正確性を検証する。

伝播テストでは、有効、欠落、不正な形式、将来バージョンのヘッダー、テナント間およびインターネット境界、Baggageの制限、キュー、リトライ、ファンアウト、ファンイン、バッチリンクを網羅します。組み立てテストでは、重複、順不同、親欠落、遅延、サイズ超過、永久に終了しないトレースを注入します。サンプリングテストでは、トレース全体の一貫性、バジェット上限、決定論的な確率決定、エラーおよびレイテンシポリシー、そして上流のヘッドドロップが復元不可能であることを証明します。

負荷テストでは、本番に準じたトレースサイズとテナントのスキューを維持します。SDKオーバーヘッド、エージェント損失、ゲートウェイ受付、ストリームラグ、アクティブトレースメモリ、決定レイテンシ、保持バイト数、インデックスラグ、トレース検索、およびフィルタ検索を測定します。障害テストでは、ゾーンの切断、ホットパーティション中のアセンブラ再起動、オブジェクトストレージの一時停止、テナントクォータの枯渇、正規オブジェクトからのホットインデックス再構築を実施します。

既知のグラフを持つ合成カナリーワークフローを、すべてのリージョンを通じて継続的に発行します。期待されるスパンが消える、親子関係が変わる、検索の鮮度が30秒を超える、またはトレースID検索がSLOに違反した場合にアラートを発報します。コレクタープロセスの稼働状態が正常であることは、トレースが完全であることや検索可能であることを証明するものではありません。

優れた回答例

「まず、トレースはログ行の寄せ集めではなく、スパンの因果関係グラフであることを明確にします。各スパンには、テナントにバインドされたトレースID、スパンID、親またはリンク、タイミング、ステータス、リソース、制限された属性、イベント、観測時刻が含まれます。サービスはHTTPまたはメッセージメタデータを介して検証済みのW3Cコンテキストを伝播します。信頼できない境界では、トレースコンテキストは認可ではなく相関データであるため、新しい内部トレースを開始してリンクします。

スパンは、プロセス内の制限付きバッファとローカルエージェントを経由してリクエストパスから外れます。エージェントはバッチ処理、圧縮、一時的なディスクスプールを行い、ビジネストラフィックをブロックする代わりに、測定された優先度の低いデータをドロップします。リージョンゲートウェイがテナントを認証し、スキーマとクォータを適用し、複製されたストリームに書き込みます。テナントとトレースIDによるパーティション分割により、すべてのトレースが1つのアセンブラに送信され、スパンIDによるリトライが冪等になります。

生のワークロードは毎秒750万スパン、5.25 GB/sです。これらすべてを不用意にテールサンプラーに送信することはありません。通常のルートは2%の一貫したヘッドサンプリングを使用します。制御された10%のクリティカルルートプールは100%でテールサンプリングに入るため、コレクターの入力は885,000スパン/秒(619.5 MB/s)になります。テールプールが10%を保持する場合、ストレージへの書き込みは210,000スパン/秒、インデックスとレプリカを除いた生データ換算で約12.7 TB/日になります。これらの境界はベンチマークの入力値であり、約束された圧縮結果ではありません。

アセンブラが最も困難な部分です。部分的なトレースを保持し、終了したルートと猶予期間を待機し、経過時間、スパン数、バイト数の制限で決定を強制します。クリティカル、エラー、低速なトレース用に制限されたキャパシティを予約し、サービスごとのバジェットを一貫したベースラインで満たします。遅延スパン用の決定をキャッシュし、不完全なトレースにラベルを付けます。上流での2%のヘッドドロップは後から復元できないため、エラーを認識した保持を真に必要とするルートは、サンプリングされずにテールプールに入る必要があります。

保持されたトレースの詳細は、トレースIDディレクトリとともに圧縮オブジェクトストレージに送られます。独立したホットインデックスは、1つのトレースサマリーと、許可リストに登録されたサービス、オペレーション、ステータス、所要時間、時間のフィールドのみを保存します。これによりカーディナリティが制御され、インデックスの再構築が可能になります。障害発生時には、エージェントは制限付きスプールを使用し、ストリームパーティションが再生され、検索が停止していてもオブジェクトの書き込みは継続し、過負荷時には保護されたクラスの前に通常のベースラインが破棄されます。コンテキスト境界、重複および遅延スパン、サンプリングバイアスと上限、ノイズの多いテナントの分離、ゾーン喪失、再構築、およびエンドツーエンドのカナリートレースを検証します。」

よくある間違い

  • 「2%サンプリングし、その後テールですべてのエラーを保持する」と述べる → 最初のステージですでに後続のエラーを含む候補トレースの98%が消去されています → 保護されたルートをサンプリングせずにテールプールに送信するか、保証を弱めます。
  • トレースIDなしでコレクター間でスパンをハッシュ分散する → 1つのテールサンプラーには断片しか見えず、偏った決定を下してしまいます → (tenant, trace_id)のすべてのスパンを同一の決定オーナーにルーティングします。
  • 完全なトレースを無期限に待つ → 非同期処理には普遍的な終了マーカーがないため、状態が無制限に増大します → ルート終了+猶予期間、最大経過時間/サイズ、明示的なワークフローポリシー、および不完全フラグを使用します。
  • traceparentを識別情報や認可として扱う → 外部の呼び出し元が相関フィールドを任意に選択できてしまいます → テナントを個別に認証し、信頼境界では新しいリンクされたトレースを開始します。
  • Baggageや任意の属性をすべてのインデックスに含める → カーディナリティ、書き込み増幅、機密データの露出が無制限になります → インデックス対象フィールドを許可リスト化し、伝播される値を制限または秘匿化します。
  • スパンを中央コレクターに同期送信する → テレメトリの障害がアプリケーションのレイテンシや可用性のリスクを高めます → 制限されたローカルキューを介して非同期にバッチ処理し、測定された損失を可視化します。
  • 各スパンを保存するがトレースサマリーを省略する → サービス、所要時間、エラーの検索で膨大な詳細データをスキャンすることになります → 正規の詳細情報に加え、トレースごとに制限された再構築可能なサマリー行を保持します。
  • 偏りのあるテールサンプルを正確なトラフィック分布と呼ぶ → エラーおよびレイテンシのルールは、異常なトレースを意図的に過剰代表させます → サンプリングメタデータを公開し、正確な集計レートにはメトリクスを使用します。
  • コレクターの稼働時間のみをテストする → コンテキストの切断、スパンの欠落、インデックスの遅延が不可視のままになる可能性があります → 既知のグラフを持つカナリーを実行し、完全性、サンプリング、鮮度、クエリSLOをアサートします。

フォローアップの質問と回答

フォローアップ1:中央の取り込みバジェットを維持したまま、すべてのエラートレースを保持することがプロダクト要件になりました。何を変更しますか?

これら2つの要件は矛盾する可能性があります。多くの場合、エラーは下流のスパンが実行された後に初めて判明するため、送信元でのヘッドサンプラーは保持を保証できません。最大生スパンレートと中央のテールキャパシティを定量化します。バジェットがすべての候補ルートを受け入れられない場合、保証対象を限定されたクリティカルルートのセットに絞り込むか、キャパシティを増やすか、あるいは将来の高レートサンプリングを開始するアプリケーションエラートリガーを追加し(過去にドロップされたスパンは再構築できないことを受け入れた上で)対応します。また、インシデントによってトラフィックのほぼすべてがエラーになる可能性があるため、「常にエラーを保持」する場合でもバイト上限を設定する必要があります。

フォローアップ2:あるメッセージが10個のプロデューサトレースからイベントを消費します。コンシューマスパンはどの親を使用すべきですか?

単一の親では10個の独立した原因を表現できません。適切なワークフロー内にコンシューマまたはバッチ処理スパンを作成し、リンク数の制限内で10個のプロデューサコンテキストへのリンクを付与します。バッチ自体に1つの配信コンテキストがある場合はそれを親とし、個々の入力はリンクのままにすることができます。クエリおよび可視化コードはDAGをサポートし、切り詰められたリンクメタデータを表示する必要があります。コンシューマスパンを10個のツリーに複製すると、所要時間とストレージが歪んでしまいます。

フォローアップ3:テールサンプラーが決定ウィンドウの前に部分的なトレースを早期退出(エビクト)させています。どのようにデバッグしますか?

アクティブなトレース数とバイト数、トレースサイズの分布、到着の遅延度、ホットパーティション、決定までの経過時間、早期退出カウンタ、テナントごとのスキューを比較します。待機ウィンドウを広げるとメモリ圧迫が悪化する可能性があります。まず、サイズ超過のトレースを制限し、ノイズの多いテナントを分離し、トレースのアフィニティを壊さずにパーティションを分割し、通常のベースラインを減らします。その後、観測された遅延スパンの価値に基づいてキャパシティを追加するかウィンドウを短縮します。シャドーポリシーを実行して、提案された変更によって保持されるエラー、低速トレース、完全性がどのように変化するかを測定します。

フォローアップ4:検索機能が2時間停止していますが、取り込みとオブジェクトストレージは正常です。APIは何を返すべきですか?

正規のトレースオブジェクトと、高耐久なインデックス変更バックログの書き込みを継続します。GetTraceは、そのパスが利用可能であればトレースIDディレクトリを使用できます。セカンダリ検索は古いas_ofデータまたは明示的な一時的利用不可状態を返します。単にサマリーがインデックス化されていないという理由だけで、新しく受け入れられたトレースが存在しないと報告してはなりません。復旧後は冪等に再生し、カウントとラグを比較し、バックログが破損している場合はオブジェクトからインデックスを再構築します。

フォローアップ5:サンプリングによって低ボリュームのサービスが完全に隠蔽されていないことをどのように証明しますか?

残りのグローバルバジェットを共有する前に、サービスごとまたはオペレーションごとの最小ベースラインバジェットを維持します。保持された各トレースとともに確率と決定理由を追跡し、トラフィックはあるものの保持されたトレースがないサービスについてアラートを発報します。合成カナリーにより、確率とは無関係にフルパスを検証します。トレースから導出されたカバレッジとメトリクスのリクエスト数を比較します。サービスがリクエストを受信しているにもかかわらずスパンが生成されない場合は、計装の欠落、伝播障害、クォータによるドロップ、ヘッド決定、テール決定、インデックス損失を区別して調査します。

公開情報ソース

関連する質問

関連面接ツール

システム設計の回答には「回答する」を使用

まず要件を明確にし、スケール、アーキテクチャ、コンポーネント選定、トレードオフの順に進めます。

ツールを見る