代表的な面接トピック

システムデザイン面接:ノイズの多いテナントを隔離し公平にスケジューリングするにはどうすればよいか?

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

質問

数千のエンタープライズテナント向けに非同期レポートサービスを設計してください。一部のテナントは月末に大量のエクスポートバーストを実行しますが、他のテナントのレイテンシや可用性を損なってはなりません。テナントの隔離、クォータ、キュー、スケジューリング、ストレージ、グレースフルデグラデーション、スケーリング、検証について説明してください。

プロンプトとコンテキスト

本質は単に tenantId を追加することではなく、パフォーマンスの分離と公平性にあります。このサービスはキュー、CPU、データベーススキャン、オブジェクトストレージ、ダウンロード帯域幅を消費する非同期レポートジョブを受け付けます。月末のバーストにより、一部のテナントがノイズを発生させます。まずサービス目標を定義し、次に何を共有し何を分離するかを説明してください。

テナントは自身のデータのみを読み取ることができ、レポートは非同期で完了してもよく、テナント間のデータ漏洩に比べれば一時的な遅延のほうが望ましいと仮定します。エンタープライズテナントは異なるプラン、リージョン、保持ポリシーを持つ場合があり、コンプライアンス、データレジデンシー、専用キャパシティは明確にすべきハードな制約事項です。公平性とは永久に均等なスループットを意味するわけではありません。契約上およびセキュリティ上の優先順位には、明示的で監査可能な重み付けを設定できます。

このシナリオはバックエンド、プラットフォーム、SRE、システムデザインの面接に適しています。AWSは主要なマルチテナント隔離パターンとしてシャッフルシャーディングを提示しており、一般的なシステムデザインの資料でもテナント隔離、クォータ、ノイジーネイバー(騒がしい隣人)は共通の設計課題として扱われています。この設問は、完全なSaaS機能セットではなく、スケジューリングと影響範囲(ブラストレイディウス)に焦点を当てています。

面接官が見ているポイント

第1に、すべての隔離境界を特定できるかです。テナントID、ジョブ、キュー、ワーカー、データベース接続、キャッシュ、オブジェクトストレージ、下り通信(egress)はすべて共有される可能性があり、入口(ingress)のみを隔離してもノイズはダウンストリームに浸透してしまいます。

第2に、クォータ、公平なスケジューリング、ハードな隔離の違いを明確に区別できるかです。テナントごとのトークンバケットはボリュームを制限し、公平なキューは次に実行する対象を選択し、シャードや専用プールは障害の範囲を限定します。これらは異なる問題を解決するものです。

第3に、大口テナントと小口テナントの間のコストトレードオフを論理的に説明できるかです。完全に専用化するとアイドルキャパシティと運用のオーバーヘッドが生じ、完全に共有するとリソース競合が発生します。優れた回答には、ティア分けと移行トリガーが含まれます。

第4に、隔離を証明できるかです。グローバルな平均値に頼るのではなく、テナント、キュー、リソースレイヤーごとにレイテンシ、拒否率、キュー滞留時間、クォータ消費量、リトライ、ドロップを測定します。

明確化のための質問

  • サービス目標は何か? インタラクティブな処理と非同期処理それぞれについて、p95、最大待機時間、成功率、リージョン可用性を定義します。
  • どのジョブが優先されるか? 契約ティア、緊急の手動処理、スケジュールされたレポート、探索的クエリなど、異なる重みを持つ可能性があります。
  • データとリソースの境界はどこか? 一部のテナントには個別のデータベース、リージョン、暗号化キー、オブジェクトストレージ、ワーカープールが必要ですか?
  • バーストおよび長期的なクォータはどのように測定されるか? 送信レート、同時実行ジョブ数、スキャンバイト数、CPU時間、ストレージ、または下り通信量(egress)ですか?
  • ユーザーにはキューイングと拒否がどのように表示されるか? 完了予測時間、リトライのガイダンス、クォータの説明、管理者向けレポートを明示する必要があります。

30秒回答

「まず、テナントおよびプランごとにレイテンシ、成功率、同時実行数、データ隔離の目標を定義し、送信クォータ、実行中の同時実行数、ダウンストリームのバジェットを切り離します。ゲートウェイはテナントを認証し、ジョブサイズと冪等性キーを検証して、耐久性のあるキューに書き込みます。スケジューラはテナントごとのトークンバケットと重み付け公平キュー(Weighted Fair Queue)を使用し、ノイズの多いテナントや規制対象のテナントは専用またはシャッフルシャード化されたワーカープールに移動できます。DBスキャン、キャッシュ、オブジェクトストレージ、下り通信も計測されます。過負荷時には、正確なステータスとキャンセル機能を提供して優先度の低い処理を拒否または延期します。テナント間認可テスト、ノイズ注入、障害テスト、そしてテナントごとのp99、影響範囲、復旧アサーションによって検証します。」

ステップ・バイ・ステップ回答

ステップ 1: リソースとサービス目標の定義

レポート処理を送信、キューイング、クエリ、生成、オブジェクト書き込み、ダウンロードに分割します。送信p95、キュー滞留時間、完了時間、ダウンロード成功率、隔離性など、それぞれに測定可能な目標を定義します。単にワーカー数を挙げるのではなく、CPU、メモリ、スキャン量、接続数、キュースロット、オブジェクトリクエスト、下り通信(egress)を予算化(バジェット化)します。

ステップ 2: 信頼できるテナントコンテキストの確立

テナントIDは、呼び出し側が指定した tenantId ではなく、認証されたクレデンシャルとサーバー側の認可から取得します。ジョブ、キューメッセージ、クエリ、オブジェクトパス、キャッシュキー、ダウンロードトークンには検証済みのコンテキストを持たせます。正当なテナントが広範なクエリによって共有リソースを枯渇させないよう、フィールド、時間枠、最大スキャン量を制限します。

text
authenticated principal
  -> authorize tenant and report definition
  -> assign quota class and priority
  -> enqueue {tenantId, taskId, costEstimate, deadline}
  -> every worker and storage call re-checks tenant scope

ステップ 3: 隔離ティアの選択

小規模テナントは、テナントクォータ、同時実行数制限、公平なスケジューリングを用いてキューとワーカーを共有できます。大量リクエストを発行するテナントや規制対象テナントには、専用のキュー、パーティション、データベーススキーマ、暗号化キー、またはワーカープールを割り当てます。AWSのシャッフルシャーディングは各テナントをワーカーの組み合わせにマッピングするため、1つのワーカーに障害が発生しても影響を受けるテナントが少なくなります。これにより、共有による効率を維持しながら影響範囲(ブラストレイディウス)を抑制できます。

ステップ 4: クォータと公平なスケジューリングの設計

受信バーストには送信トークンバケット、処理中のジョブには同時実行数制限、スキャンバイト数やCPUにはコストバジェットを使用します。重み付け公平キューまたはテナントごとの仮想キューにより、単一のテナントがすべてのワーカーを占有するのを防ぎます。テナント内では、優先度、デッドライン、キュー滞留時間順に並べ替えます。拒否は、無限のリトライを促すのではなく、一時的な過負荷またはクォータの状態として説明可能であるべきです。

制御制限対象目的超過時の動作
Submission bucketテナントごとのレートとバースト入口のピークを制限延期するか、リトライ可能なステータスを返す
In-flight cap実行中のジョブ1つのテナントがワーカーを埋め尽くすのを防ぐキューに入れ、予測待機時間を表示
Cost budgetスキャンバイト数、CPU、メモリ大規模な処理がダウンストリームに悪影響を与えるのを防ぐキャンセル、分割、または範囲の絞り込み
Weighted fair queueディスパッチにおけるテナントのシェアリソース枯渇(スタベーション)の防止滞留時間の優先度を考慮した重み付けラウンドロビン
Dedicated shard大規模または規制対象テナントパフォーマンスおよび障害の影響を限定分離プールへ移動またはデグレード

ステップ 5: ダウンストリームリソースの保護

スケジューラがデータベース、キャッシュ、オブジェクトストレージのバジェットを確保した後にのみジョブを開始します。レポートにはリードレプリカ、時間枠、スキャン制限を使用します。結果をテナントおよびリージョンごとにパーティション分割し、短寿命のダウンロード認可を発行します。接続、キャッシュ、スレッド、下り通信がグローバルに共有されたままであれば、入口での公平性だけではダウンストリームの枯渇を防げません。重要な依存関係には独自の同時実行数制限と制限付きキューを設けます。

ステップ 6: バースト、障害、および復旧の処理

ジョブの状態、クォータのスナップショット、冪等性キー、キャンセル状態を永続化します。クラッシュしたワーカーはリトライできますが、結果の書き込みはバージョンまたは結果キーを通じて冪等でなければなりません。依存関係が利用できなくなった場合は、影響を受けるクラスのみを一時停止し、キューの滞留時間と見積もりを保持し、大規模なリトライストームを回避します。復旧時には、すべてのバックログを一度に解放するのではなく、p99、エラー、クォータを監視しながら、テナントと優先度ごとに段階的に受付を増やします。

ステップ 7: スケール、移行、および検証

平均CPU使用率だけでなく、有効なスループット、キュー滞留時間、リソース使用率、テナントの重み付けに基づいてスケールします。テナントを共有プールから専用シャードに移行する際は、冪等なジョブ状態と結果パスを維持し、段階的に切り替え、ロールバックを可能にしておきます。テナント間の認可テスト、ノイズ注入、ワーカー単一障害、低速データベース、キュー復旧、キャンセル、大規模テナントの移行をテストし、各テストで他のテナントが依然として目標を満たしているか確認します。

質の高い模範回答

「レポート処理を送信、キューイング、クエリ、生成、ストレージ、ダウンロードに分割し、それぞれに対してレイテンシ、成功率、隔離の目標を定義します。テナントIDは認証されたコンテキストから取得し、サーバーがレポート定義を再認可します。リクエスト内のテナントフィールドは単なる入力値であり、セキュリティ境界ではありません。ジョブはテナント、コスト見積もり、冪等性キー、デッドラインとともに耐久性のあるキューに入ります。

小規模テナントはワーカーを共有しますが、それぞれ送信レート、処理中ジョブ数、スキャンバイト数、ストレージのクォータを持ちます。滞留時間を優先した重み付け公平スケジューリングにより、月末のバーストがすべてのワーカーを占有するのを防ぎます。大量リクエストを発行するテナントや規制対象テナントは、ワーカー障害やホットテナントの影響範囲を小さくするために、専用キュー、パーティション、またはシャッフルシャード化されたワーカープールに移行できます。データベース接続、キャッシュ、オブジェクトストレージ、下り通信にもテナントまたはクラスごとのバジェットを割り当てます。

超過時には、キュー状態または一時的な過負荷状態を正直に返し、キャンセルをサポートします。クライアントが無制限にリトライすることは許可しません。ワーカーは冪等な結果キーを使用し、依存関係の障害時には影響を受ける処理のみを一時停止し、復旧時はテナントと優先度に応じて段階的に処理を再開します。

検証には、テナント間アクセステスト、単一テナントのバースト注入、ワーカーおよびデータベースの障害注入、キューのリプレイ、キャンセル、移行テストを用います。各テナントのp99、キュー滞留時間、拒否率、リソース使用量、データ漏洩の検証結果を確認します。隔離プールを拡張したり重み付けを調整したりするのは、小規模テナントと上位ティアのテナントの双方が目標を達成できていることを確認した上で行います。」

よくある間違い

  • リクエストの tenantId を信用する → 呼び出し元がスコープを偽装できる → 認証から導出し、ダウンストリームで再チェックする。
  • すべてのテナントに固定ワーカーを1つ割り当てる → アイドルキャパシティが増加し、依然として障害が波及する → 必要に応じてリスクティアと組み合わせシャード(シャッフルシャーディング)を使用する。
  • 送信レートのみを制限する → 処理中のジョブがダウンストリームを圧迫し続ける → 同時実行数、コスト、依存関係も制限する。
  • 公平性の判断にグローバル平均を使用する → 小規模テナントのテールレイテンシが見えなくなる → テナントごとにp95、p99、キュー滞留時間、拒否率を記録する。
  • 過負荷時に無制限にリトライする → リトライ増幅によりサービス全体がダウンする → 明示的な状態を返し、冪等なリトライと共有バジェットを使用する。
  • データベースバジェットを考慮せずにワーカーを増やす → 依存関係がボトルネックになる → すべてのリソースレイヤーをエンドツーエンドでバジェット化する。
  • 復旧時にすべてのバックログを一斉に解放する → 新たなスパイクが発生する → ヒステリシスと段階的な受付(レートランプ)を使用する。
  • 冪等な状態を持たずに移行する → ジョブの重複や結果の消失が発生する → バージョン、結果キー、ロールバック機構を使用する。

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

フォローアップ 1: シャッフルシャーディングは通常のシャーディングとどう違いますか?

通常のシャーディングはテナントを単一の固定シャードに配置するため、1つのシャードの障害がそこに配置された全テナントに影響します。シャッフルシャーディングは各テナントを重複が制限されたワーカーの組み合わせにマッピングするため、1台のワーカー障害によって影響を受けるテナントのセットを縮小できます。ただし、キャパシティ管理、リバランス、ホットテナントの移行に関する考慮事項が増加します。

フォローアップ 2: プレミアムテナントは公平なスケジューリングをバイパスできますか?

契約上または有料の明示的な重み付けを与えることはできますが、全体のキャパシティ、隔離性、セキュリティ境界は維持する必要があります。プレミアム処理のためにバジェットを確保しつつ、一般テナント向けの最低限のサービス目標を記録します。「優先」とは、他者を無制限にプリエンプト(横取り)することを意味してはなりません。

フォローアップ 3: 1つのレポートがデータベース全体をスキャンする場合はどうしますか?

構文解析およびクエリプラン作成時にコストを見積もり、時間範囲の指定を必須とし、バイト数と同時実行数を制限し、バジェットを超過する処理は分割、延期、または拒否します。データベースの接続プールを拡大するだけではプレッシャーがストレージ層に移行するだけであり、根本的な解決策にはなりません。

フォローアップ 4: テナント間のデータ漏洩がないことをどのように証明しますか?

API、キューリプレイ、ワーカー、キャッシュ、オブジェクトパス、エクスポート、管理者ツール全体にわたり、認証されたプリンシパルからアクセスマトリクスを構築します。コンテキストが欠落または偽装されている場合にデフォルトで拒否されるネガティブテストを追加し、実際の結果データに対してテナントラベルと内容を検証(アサート)します。

公開情報ソース

関連する質問

関連面接ツール

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

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

ツールを見る