プロンプトとスコープ
あるクラスタでのデータベース、キュー、またはデプロイの障害がすべてのテナントに影響を及ぼす可能性があるグローバルSaaSを担当しています。セルベースアーキテクチャを設計してください。各セルは固定されたテナントセットにサービスを提供する、独立して運用可能なシステムの完全なコピーであり、エントリー層は安定したマッピングによってリクエストをターゲットセルにルーティングします。
テナントのパーティショニング、ルーティングディレクトリ、セル内のコンピュートおよびデータ境界、セル間レポーティング、リリース、移行、キャパシティ、ディザスタリカバリを網羅してください。AWSはセルを独立したレプリカとして説明し、ユーザーとセルのマッピングを高可用性ストレージに保存します。また、そのバルクヘッドガイダンスでは、単一のエンドポイントの背後にあるパーティションキーによるルーティングが説明されています。
面接官が評価するポイント
- 障害スコープ、テナントの一貫性、および許容可能な縮退運用を最初に定義しているか。
- セルが単にステートレスサービスを複製したものではなく、真の障害ドメインになっているか。
- ルーティング、コントロールプレーン、共有依存関係、セル間クエリのリスクを特定できているか。
- 新しいセルの追加、リバランス、テナント移行にロールバック可能な手順が用意されているか。
- セルレベルのキャパシティ、エラー、依存関係のメトリクスによってブラスト半径の主張が証明されているか。
システムデザイン面接の参考文献では、セルベースアーキテクチャを非常に大規模なシステム向けの分離パターンとして扱っています。優れた回答では、信頼性の向上がインフラや運用の重複コストに見合うケースを説明できます。セルはマイクロサービスの同義語ではありません。
回答前の明確化のための質問
- ターゲットとする障害スコープは、1テナント、1セル、1つのアベイラビリティゾーン(AZ)、あるいはリージョン全体のいずれですか?
- テナント間でデータ、グローバル検索、またはテナント横断の集計を共有してもよいですか?
- どの操作に線形化可能性(Linearizability)が必要で、どのレポートなら遅延や結果整合性を許容できますか?
- 移行中に短時間の読み取り専用期間を設けることは可能ですか?データの保持地(データレジデンシー)に関する制約はありますか?
- 可用性目標、テナント数、成長率、セルあたりのキャパシティ、リリースの頻度はどの程度ですか?
30秒の回答フレームワーク
安定したテナントキーを固定のセルにマッピングします。各セルはコンピュート、キュー、キャッシュ、プライマリデータストレージを保持し、グローバルコントロールプレーンはバージョン、キャパシティ、マッピングのみを管理します。エントリールーターは高可用性ディレクトリを読み取り、障害が発生したセルのみを切り離します。セル間レポートは非同期集計を使用し、クエリによって共有データベースが再作成されないようにします。セルの作成、移行、リリースには、小さく、可測で、ロールバック可能なステップを採用し、セルレベルのSLOによって障害境界を証明します。
ステップごとの詳細な回答
ステップ 1:セルの境界と障害の前提を定義する
セルを、独立してデプロイおよび復旧できる完全なコピー(API、ワーカー、キャッシュ、データベース、オブジェクトストレージのプレフィックス、監視)として定義します。共有のアイデンティティ、課金、設定サービスには明示的な障害バジェットが必要です。共有コントロールプレーンが利用不可になった際にすべてのセルがブロックされる場合、データプレーンは完全に分離されていません。
ステップ 2:パーティションキーとルーティングディレクトリを選択する
安定したパーティションキーとして tenant_id を使用します。ディレクトリには、テナントとセルのマッピング、バージョン、移行状態、キャパシティが保存されます。ルーターはまずローカルキャッシュを読み取り、高可用性ディレクトリからリフレッシュします。バージョン番号とリース(lease)により、移行中に古いルートが2つのセルに二重書き込みするのを防ぎます。クライアントには単一のホスト名が見え、ルーターがリトライ境界を管理します。
ステップ 3:セル内データプレーンを構築する
各セルは独自のプライマリデータベースとメッセージキューを持ち、テナントデータがセル間で同期的に書き込まれることはありません。レプリカ、キャッシュ、オブジェクトストレージはセル識別子を保持し、バックアップにもそのメタデータが維持されます。グローバル設定は、単一のグローバルデータベースにホットトラフィックを送るのではなく、読み取り専用スナップショットまたはバージョン管理されたロールアウトを使用します。
ステップ 4:セル間クエリを処理する
各セルは変更ストリーム(change stream)を出力し、グローバル分析レイヤーが消費する集計テーブルを構築します。レポートには、リアルタイムの完全性を主張するのではなく、データのタイムスタンプと欠落セルのマーカーを含めます。強整合性が必要なテナント横断操作は、範囲を絞り込むか、非同期にするか、あるいはより大きな共有障害ドメインを明示的に受け入れる必要があります。リクエストパス上での2相コミットは避けてください。
ステップ 5:障害パスと縮退パスを設計する
ヘルスチェックでは、セル内の依存関係、ルートの到達性、ビジネスの正確性をカバーします。セルに障害が発生すると、ディレクトリはそれをドレイン中(draining)としてマークし、新しいリクエストを停止します。プロダクトが許容する場合は、読み取りキャッシュや非同期処理を縮退させます。レプリケーション、冪等性、認可の境界が証明されるまで、テナントを任意のセルに移動してはいけません。フェイルオーバーによって重複書き込みが発生する可能性があります。
ステップ 6:セルの追加とキャパシティのリバランス
インフラテンプレートから空のセルを作成し、シンセティックトラフィックとシャドウリードを実行してから、少数のテナントセットを受け入れます。キャパシティシグナルには、CPU、データベース接続数、キューの遅延、ストレージの増加、テナントあたりのコストが含まれます。リバランスでは、マッピングバージョンを固定し、データをコピーして検証し、短い書き込みハンドオフを実行して、古いセルと新しいセルを監視します。障害発生時は、古いデータを削除するのではなくマッピングをロールバックします。
ステップ 7:リリースとバージョンを統制する
コントロールプレーン、セルテンプレート、ビジネスロジックのバージョンを個別にリリースします。まず1つのセルでカナリアリリースを行い、セル単位で順次拡大します。新しいバージョンが古いバージョンで読み取れないフィールドを書き込むことがないよう、互換性ウィンドウを維持します。バージョン分布とエラーをセル単位で可視化します。グローバルの平均値によって単一セルの不良バージョンが隠れてはなりません。
ステップ 8:ブラスト半径と運用コストを検証する
単一のセルにデータベース、キュー、ルーティングディレクトリ、デプロイの障害を注入し、想定したテナントのみが影響を受けることを確認します。セルの可用性、エラーバジェット、セル間リクエストの割合、移行のロールバック時間、共有コントロールプレーンへの依存度、予備キャパシティを追跡します。セル数が少なすぎて障害を分離できない場合や、重複運用のコストが信頼性の向上を上回る場合は、よりシンプルなパーティションまたはバルクヘッド設計を選択してください。
模範回答
tenant_id を固定のセルにマッピングします。各セルはAPI、キュー、キャッシュ、プライマリストレージを個別に実行し、コントロールプレーンはバージョン、キャパシティ、マッピングのみを管理します。単一ホスト名のルーターがバージョン管理された高可用性ディレクトリを読み取り、障害が発生したセルは他の場所で未検証の書き込みを受け入れるのではなくドレイン(排出)されます。セル間レポーティングは変更ストリームを介して非同期に行われます。移行には、コピー、検証、短時間のハンドオフ、およびロールバック可能なマッピングを使用します。セルのSLO、共有依存関係の割合、ロールバック時間、障害訓練によってブラスト半径の主張を証明します。分離コストがそのメリットを上回る場合は、よりシンプルなバルクヘッドを使用します。
よくある間違い
- ステートレスサービスのみを複製する → 共有データベースが単一障害点として残る → 各セルのデータとキューの境界を明確に引く。
- 障害時にテナントを無作為に移動する → 重複書き込みや認可の不一致が発生する → 事前にレプリケーション、冪等性、ルートバージョンを検証する。
- リクエストパス上でセル間を集計する → 新たなグローバル障害ドメインが生まれる → データタイムスタンプマーカー付きの非同期集計を使用する。
- グローバルヘルスチェックのみを使用する → 問題のあるセルが平均値に隠れてしまう → セルレベルのSLOとバージョン分布を記録する。
- 移行中にルートを直接変更する → 新旧の書き込みが重複する → マッピングバージョン、コピー検証、ロールバックを使用する。
- すべての依存関係に独自のセルを割り当てる → コストと運用の肥大化を招く → まずブラスト半径とキャパシティのメリットを定量化する。
フォローアップ質問と回答
ルーティングディレクトリに障害が発生した場合はどうなりますか?
バージョン管理されたローカルキャッシュと読み取り専用スナップショットを保持し、マッピングの変更を制限して、既存のテナントが元のセルで継続できるようにします。ディレクトリが復旧するまで、広範なリバランスは行いません。
管理者レポートがセル全体でリアルタイムである必要がある場合はどうしますか?
許容される遅延とデータ欠落のセマンティクスを明確にします。強整合性が必要な場合は、操作範囲を狭めるか、より大きな共有障害ドメインを受け入れる必要があります。通常のレポートにはタイムスタンプ付きの非同期集約を使用すべきです。
セルが満杯になった場合、どのようにテナントを移行しますか?
データをコピーして検証し、新しいマッピングバージョンを公開し、短い書き込みハンドオフを調整して、トラフィックを徐々に移行します。整合性が証明されるまで古いセルを維持し、証明されない場合はマッピングをロールバックします。
一部のセルにのみ特定バージョンをデプロイするのは安全ですか?
はい。互換性のあるスキーマ、バージョンの可観測性、および明示的なロールアウト順序があれば安全です。グローバルの成功率をセルごとのエラーバジェットの代替にしてはなりません。
障害が広がらなかったことをどのように証明しますか?
単一セル内でデータベース、キュー、ルーティング、デプロイの障害訓練を実施します。影響を受けたテナント、セル間リクエスト、復旧時間、および共有依存関係への呼び出しを記録します。
セルベースアーキテクチャを採用すべきでないのはどのような場合ですか?
テナント規模や障害コストが低い場合、またはテナント間の強整合性が支配的なシステムでは、重複するリソースと移行の複雑さに見合うリターンが得られない可能性があります。
セル間でアイデンティティと課金を共有するにはどうすればよいですか?
共有サービスをリクエスト頻度の低いコントロールプレーンに配置し、読み取り専用の結果をキャッシュして、縮退モードを定義します。課金の書き込みには冪等性キーと補償トランザクションを使用し、共有サービスの障害がすべてのデータプレーンに波及しないようにします。