プロンプトと適用シナリオ
DropboxやGoogle Driveに類似したクラウドファイルストレージおよびマルチデバイス同期サービスを設計します。登録ユーザー数は5,000万人、日間アクティブユーザー(DAU)は500万人です。各ユーザーは平均して10 GBの論理データを保存します。システムは1日あたり1億件の新しいファイルバージョンを受信し、バージョンごとに4 MBの新規または変更されたコンテンツが含まれます。ピーク時のトラフィックは1日の平均の5倍です。ファイルサイズは最大50 GBで、オンラインのデバイスは作成、更新、移動、削除を5秒以内に認識する必要があり、メタデータサービスは99.99%の可用性を目標とします。
規模、レイテンシ、可用性、および4 MiBのターゲットチャンクサイズは面接用の前提条件であり、特定のストレージ製品の公開パフォーマンスコミットメントではありません。対象範囲には、アップロード、ダウンロード、再開可能な転送、バージョン復元、マルチデバイス同期、オフライン編集、競合コピー、シンプルな共有、および削除が含まれます。文字レベルの共同編集、Officeドキュメントのセマンティックマージ、完全なエンタープライズ認可システム、およびアクティブ-アクティブなクロスリージョン書き込みは対象外です。
2026年現在でも公開されているシステム設計の課題では、Dropbox、Google Drive、または汎用的なファイル同期サービスを用いて、大容量ファイルのチャンク分割、差分同期、バージョン管理、オフライン操作、および競合について質問されます。オブジェクトストレージの公式ドキュメントでもマルチパートアップロードのエンジニアリング上の有用性が示されています。パートを並列にアップロードでき、失敗したパートは個別に再試行できる一方で、放棄されたパートには中止(abort)やライフサイクルによるクリーンアップが必要です。面接の目的は、コンテンツ転送を名前空間(namespace)の状態から分離し、復元と削除に関する正確性のループを完結させることであり、単一企業の内部アーキテクチャを暗記することではありません。
面接官が評価するポイント
第一に、候補者がファイルコンテンツとメタデータを分離できるかです。巨大なバイトシーケンスは、耐久性があり安価で不変なオブジェクトストレージに配置すべきです。名前、親子関係、現在のバージョン、削除マーカー、および同期カーソルには、条件付き書き込みと順序付けられた変更が必要です。50 GBのファイルをリレーショナルデータベースに格納したり、オブジェクトキーを完全なディレクトリモデルとして使用したりすると、更新、移動、トランザクションコミット、復元が脆弱になります。
第二に、アップロードに明確な単一の公開ポイント(publication point)が存在するかです。クライアントは不足しているチャンクを並列にアップロードできますが、バージョンが可視化されるのは、サーバーがすべてのチャンクを検証し、チェンジログとともにcurrentVersionIdをアトミックに更新した後のみです。そうでない場合、メタデータが存在しないコンテンツを参照したり、アップロードされたバイトがユーザーに決して表示されなくなったりする可能性があります。
第三に、同期プロトコルが通知の喪失、重複、順序の入れ替わりに耐えられるかです。プッシュメッセージは「何かが変更された」というヒントにすぎません。デバイスは信頼できる変更を取得(pull)するために永続化されたカーソルを使用する必要があります。数日間オフラインだったデバイス、再インストールされたクライアント、期限切れのカーソルはすべて復元パスを必要とします。WebSocket接続は信頼できる情報源(Single Source of Truth)ではありません。
第四に、並行性セマンティクスが誠実であるかです。2台のオフラインデバイスが同じ古いバージョンから同一の通常のバイナリファイルを変更した場合、汎用サービスがそれらを確実にマージすることはできません。条件付きコミットが失敗した場合は、Last-Writer-Wins(最後の書き込み優先)を暗黙的に適用するのではなく、両方の結果を保持して競合コピーを作成する必要があります。Dropboxの公式ヘルプドキュメントでも同様に、同時編集やオフライン編集によって競合コピーが生成され、ユーザーがマージする必要があることが説明されています。
最後に、回答がキャパシティ、コスト、および領域の回収を関連付けているかです。候補者は論理キャパシティと重複排除後の物理キャパシティを区別し、バージョンのコミット数とバイトスループットを見積もり、孤立(orphan)チャンク、保持されたバージョン、削除トゥームストーン、クォータ、ホットな名前空間、およびガベージコレクションが単一の瞬間的な参照カウントに依存できない理由を説明する必要があります。
回答前の明確化のための質問
- 同期されるコンテンツは何か? 通常のファイルとディレクトリ。文字レベルのリアルタイムコラボレーションは対象外。
- どのような一貫性が必要か? アップロード元のデバイスにはRead-Your-Write(自分の書き込みの即時読み取り)の動作。他のオンラインデバイスは5秒以内に収束。
- 増分履歴はどのくらいの期間保持されるか? 30日間と想定。これより古いカーソルは、差分同期を再開する前に名前空間のスナップショットが必要。
- 同時編集はどのように処理されるか? 特定の
baseVersionIdからのコミットのうち1つだけが最新(current)になり、後からの結果は競合コピーとして保持される。 - 削除によって直ちにバイト領域を回収できるか? 否。トゥームストーンを書き込み、オフライン同期と復元のために30日間保持する。
- 重複排除はユーザー間でグローバルに行われるか? コンテンツ存在の漏洩リスクと暗号化の結合を減らすため、デフォルトではアカウントまたはテナントスコープの重複排除とする。
- どのような共有機能がスコープに含まれるか? ファイルまたはディレクトリの読み取り専用リンク。複雑な組織権限はフォローアップとする。
- 暗号化と悪意のあるファイルはどのように処理されるか? 転送中および保存時の暗号化、有効期限の短い署名付きURL、非同期マルウェアスキャン。エンドツーエンド暗号化は対象外。
- リージョンはどのように書き込みを受け付けるか? 各名前空間には1つのホーム書き込みリージョンがある。オブジェクトはリージョン間でレプリケーション可能で、メタデータはディザスタリカバリ用の非同期レプリケーションを行う。
- インスタントアップロード(瞬時アップロード)のヒットは保証されるか? 固定の重複排除率は想定しない。論理クォータはユーザーに見えるサイズで課金し、物理的な削減量は個別に測定する。
30秒の回答フレームワーク
「約4 MiBの不変チャンクをオブジェクトストレージに保存し、ディレクトリ、現在のバージョン、マニフェスト、トゥームストーン、順序付けられた変更を強力な一貫性を持つメタデータに保持します。クライアントは不足しているチャンクのみをアップロードし、baseVersionIdと冪等性キーを用いてアトミックにコミットします。デバイスはカーソルを永続化し、通知を/changes?cursor=のトリガーとしてのみ使用するため、通知が失われてもデータは失われません。オフラインでの同時コミット時は競合コピーが保持されます。1日あたり1億バージョンにおいて、5倍のピーク時は約6,000コミット/秒となり、400 TBの日間イングレスはピーク時に約25 GB/sに達します。削除時はトゥームストーンを保持し、猶予期間とマニフェストの照合を経てからのみチャンクが回収されます。」
ステップバイステップの詳細設計
まず5つの不変条件(不変項)から始めます:
- 公開されたバージョンは、存在し整合性チェックに合格したチャンクのみを参照する。
- コミットは、
baseVersionIdが現在のバージョンと依然として等しい場合にのみcurrentVersionIdを置き換える。 - 変更シーケンス番号は名前空間内で厳密に増加し、デバイスのカーソルは進むことしかできない。
- 削除はトゥームストーンを書き込む。同期および復元ウィンドウの間、まだ参照される可能性があるデータは物理的に削除されない。
- ガベージコレクションは、猶予期間とマニフェストの照合を経てもなお参照が存在しないことを確認した後にのみチャンクを削除する。
ステップ1:クライアント、メタデータプレーン、コンテンツプレーンの分離
クライアントは、ファイルウォッチャー、ローカルインデックス、耐久性のある操作ジャーナル、チャンカー、同期エンジンを持ちます。クラッシュ後、すべてのファイルを再スキャンしてアップロードするのではなく、どのチャンクがアップロード済みで、どのコミットが不確定であるかを復元します。サーバーは、APIゲートウェイ、認証およびクォータチェック、メタデータサービス、アップロードコーディネーター、オブジェクトストレージ、名前空間チェンジログ、通知サービス、ダウンロードCDN、マルウェアスキャナー、ガベージコレクターを持ちます。
メタデータはnamespaceIdによってルーティングされます。個人ドライブが1つの名前空間であり、共有フォルダを別の名前空間にすることができるため、認可、順序付けられた変更、ホットスポットの分離を1つの境界内に維持できます。各名前空間は当初、アベイラビリティゾーン間でメタデータを同期レプリケーションする1つのホーム書き込みリージョンを持ちます。ダウンロードは近くのCDNまたはオブジェクトレプリカを使用できます。これにより、2つのリージョナルリーダーが競合するディレクトリ更新を同時に受け付けることを防ぎます。
ステップ2:データモデルの定義
FileEntry(id, namespaceId, parentId, name, type, currentVersionId, deletedAt)
FileVersion(id, fileId, baseVersionId, size, manifestHash, createdBy, createdAt)
VersionChunk(versionId, ordinal, chunkHash, size)
UploadSession(id, fileId, baseVersionId, state, expiresAt, idempotencyKey)
Change(namespaceId, seq, entityId, operation, versionId, createdAt)ディレクトリツリーは安定したfileIdおよびparentIdの値を使用するため、移動や名前変更を行ってもコンテンツをコピーすることなくメタデータを変更できます。FileVersionは不変であり、順序付けられたVersionChunkの行がそのマニフェストを構成します。manifestHashはマニフェストを検証しますが、各チャンクのチェックサムを置き換えるものではありません。UploadSessionはセッション状態とその冪等性キーを保存します。Change.seqは名前空間内で単調増加し、削除もログに記録される操作の1つです。
(namespaceId, parentId, normalizedName)に対する条件付き制約で名前の一意性を強制します。プロダクトはファイル名の大文字・小文字の正規化(case normalization)を明示的に定義する必要があります。そうしないと、Windows、macOS、Linuxのクライアント間で、2つの名前が競合しているかどうかについて不一致が生じる可能性があります。
ステップ3:再開可能なマルチパートアップロードの設計
POST /files/{fileId}/upload-sessions
{ baseVersionId, size, chunks[], idempotencyKey }
-> { uploadSessionId, missingChunks[], signedUrls[] }
PUT {signedChunkUrl}
Content-Checksum: ...
POST /upload-sessions/{uploadSessionId}/commit
{ manifestHash, idempotencyKey }
-> { fileVersionId, changeSeq }
GET /files/{fileId}/download-manifest
-> { fileVersionId, chunks[], signedUrls[] }クライアントは約4 MiBのチャンクから開始し、強力なハッシュを計算します。サーバーはアカウントまたはテナント内でのみ既存のチャンクを検索し、不足しているチャンクに対してオブジェクトおよび操作スコープが限定された有効期限の短い署名付きURLを発行します。クライアントは制限された並行性でアップロードし、失敗したパートのみを再試行します。AWSおよびAlibaba Cloudの公式マルチパートドキュメントはいずれも、初期化(initiate)、パートアップロード(upload-parts)、完了(complete)のセッションモデルを採用しています。また、未完了のパートはストレージを消費し続けるため、セッションには有効期限が必要であり、長期間放棄されたアップロードには明示的な中止(abort)が必要であると記されています。
固定サイズのチャンクはシンプルであり、ほとんどのファイルで適切に並列化されます。ワークロードが先頭付近に頻繁に数バイトを挿入する場合、それ以降のすべての固定境界がシフトし、ハッシュが変化します。コンテンツ定義チャンク分割(CDC: Content-Defined Chunking)は、CPUと実装の複雑さと引き換えに、より多くの変更されていないデータを再検出できます。まずは固定チャンクから開始し、観察された編集パターンによって正当化される場合にのみアップグレードしてください。
ステップ4:バージョンコミットを唯一の公開境界にする
コミットエンドポイントは、まずidempotencyKeyによって既存の結果を検索し、次にチャンクサイズ、ハッシュ、認可、クォータを検証します。1つのメタデータトランザクション内で、以下を実行します:
FileEntry.currentVersionIdをロックまたは条件付きで読み取る。- リクエストの
baseVersionIdと依然として等しいことを検証する。 - 不変の
FileVersionとVersionChunkマニフェストを書き込む。 currentVersionIdを更新する。- 次の
Change.seqとトランザクショナルアウトボックスレコードを追加する。
オブジェクトのバイトデータはメタデータトランザクションの前に完了しているため、トランザクションが存在しないチャンクへの参照を公開することはありません。コミット後の通知の失敗は正確性に影響しません。アウトボックスが再試行し、デバイスはカーソルによってプルできます。コミットのレスポンスが失われた場合、同じ冪等性キーで再試行すると、別の論理バージョンを作成したりクォータを二重請求したりすることなく、元のfileVersionIdが返されます。
ステップ5:カーソルを使用したデバイスの同期
GET /changes?namespaceId={id}&cursor={lastSeq}&limit=1000
-> { changes[], nextCursor, hasMore }デバイスは、lastSeqとローカルファイルインデックスを同一の永続トランザクションに保存します。「名前空間が変更された可能性がある」という通知を受信した後、hasMore=falseまでプルし、作成、更新、移動、トゥームストーンを順番に適用し、その後にのみ新しいカーソルをコミットします。seqにより、リプレイは冪等になります。通知の順序が入れ替わってもプル結果には影響しません。すべての通知が失われた場合でも、フォアグラウンド復帰や定期チェックによって新しいシーケンスが検出されます。
カーソルが30日間の保持ウィンドウより古い場合、サービスは整合性のある名前空間スナップショットの場所とともにcursor_expiredを返します。クライアントはスナップショットをロードし、ローカルの未コミット操作を調整(リコンサイル)して、スナップショットのウォーターマークから再開します。単純にすべてのローカルファイルを削除してはなりません。通知はレイテンシの最適化手段であり、カーソルログこそが同期プロトコルの実体です。
ステップ6:競合、削除、およびバージョン復元の処理
デバイスAとBが両方ともオフラインでバージョン10を編集したとします。AはbaseVersionId=10を指定してバージョン11をコミットします。Bのその後の条件付きコミットは失敗します。サービスはBがアップロードしたコンテンツを保持し、「名前 (Bの競合コピー)」などの新しいエントリまたは競合バージョンを作成し、名前空間の変更を追加します。通常のバイナリファイルが無言で自動マージされることはありません。テキストまたはドキュメント固有のマージは、別の製品機能です。
削除操作はdeletedAtを更新し、トゥームストーンを追加します。オンラインのデバイスはエントリをゴミ箱に移動し、オフラインのデバイスは再接続時に削除を認識できます。過去のバージョンとチャンク参照は、30日間の復元ウィンドウ内では有効なままです。その後、コレクターは保持されているマニフェストによって参照されているチャンクのセットを計算し、参照されていない候補にマークを付け、猶予期間を待機し、削除前にもう一度照合します。再試行、遅延イベント、修復ジョブによって瞬間的な参照カウントが誤った値になる可能性があるため、それを取り返しのつかない削除の唯一の根拠にすることはできません。
ステップ7:キャパシティの見積もりとホットスポットの分離
論理ストレージは50 million × 10 GB = 500 PBです。レプリケーション、履歴、重複排除によって物理キャパシティは変化しますが、プロンプトには比率が示されていないため、正確な物理値を提示すると捏造になってしまいます。1日の論理イングレスは100 million × 4 MB = 400 TBであり、平均約4.6 GB/s、ピーク時は約25 GB/sです。バージョンのコミット数は平均100,000,000 / 86,400 ≈ 1,157/sで、5倍のピーク時には約6,000/秒となります。
各変更が平均3台のオンラインデバイスに通知される場合、通知はピーク時に約18,000/秒に達する可能性があります。通知はファイルごとの信頼性の高いメッセージにするのではなく、「この名前空間が変更された」という形に統合(coalesce)できます。メタデータをnamespaceIdでハッシュシャード化し、1つの名前空間に対する順序付けられた書き込みを1つのプライマリシャードに保持します。非常に大きな共有スペースはホットになる可能性があります。一括ディレクトリ操作をレート制限し、通知を統合し、確証がある場合にのみfileIdでファイルレコードをサブシャード化しつつ、独立した名前空間シーケンスジェネレーターを維持します。
ステップ8:障害処理、セキュリティ、および検証ループの完結
- アップロードの中断:セッションを照会し、不足しているパートのみをアップロードする。ライフサイクル処理により放棄されたセッションを期限切れにする。
- パートはアップロードされたがコミットに失敗:パートは一時的な孤立状態となり、猶予期間の後にマニフェスト照合によって回収される。
- コミットは成功したが通知に失敗:トランザクショナルアウトボックスが再試行し、カーソルによるプルによって復元される。
- コミットは成功したがレスポンスが喪失:同一の冪等性キーにより元の結果が返される。
- オフラインでの同時書き込み:
baseVersionId条件が失敗し、サービスは競合コピーを保持する。 - 破損したチャンク:アップロードおよびダウンロード時に強力なハッシュを検証し、無効なコンテンツが公開マニフェストに入らないようにする。
- 期限切れのカーソル:スナップショットをロードし、そのウォーターマークから再開する。
- ホームリージョンが書き込み不能:書き込みを停止するか、明確なRPO/RTO手順のもとでフェイルオーバーする。2つのホームライターを決して許可しない。
署名付きURLは有効期限が短く、アカウント、オブジェクト、サイズ、操作にバインドされている必要があります。サーバーはコミット時に認可とクォータを再確認します。グローバルなユーザー間インスタントアップロードはコンテンツの存在に関するサイドチャネルを生み出し、ユーザーごとの暗号化と削除権限を結合させてしまうため、重複排除はデフォルトでテナントスコープとします。主要なメトリクスには、アップロードおよびコミットのp99、同期ラグ、期限切れカーソル、競合コピー、孤立チャンクバイト数、重複排除ヒット率、GC候補と実際の削除の差分、ホットな名前空間、チェックサムエラー、および復元成功率が含まれます。
検証では、50 GBファイルの再開可能な転送、各アップロード段階後のクラッシュ、重複コミット、通知の喪失と順序の入れ替わり、オフラインでの同時編集、削除後に古いデバイスが復帰するケース、チェックサムの破損、プライマリシャードのフェイルオーバー、期限切れカーソル、クォータ境界、および誤削除に対するGCの保護をカバーします。最も重要なエンドツーエンドのアサーションは、すべての可視化されたfileVersionIdが完全で検証済みのコンテンツとしてダウンロード可能であり、復元ウィンドウ内のバージョンが決して回収されないことです。
質の高い模範解答
「まずコンテンツプレーンをメタデータプレーンから分離します。ファイルはオブジェクトストレージ内で約4 MiBの不変チャンクに分割されます。ディレクトリ、安定したfileId値、現在のバージョン、バージョンマニフェスト、トゥームストーン、名前空間シーケンス番号は、条件付き書き込みをサポートするメタデータレイヤーに配置されます。移動や名前変更は、履歴を上書きすることなくメタデータを更新します。
アップロード時、クライアントはチャンクをハッシュ化し、baseVersionIdと冪等性キーを使用してセッションを作成します。サーバーは、テナントスコープで不足しているチャンクに対してのみ、有効期限の短い署名付きURLを返します。すべてのチャンクがアップロードされ検証された後、メタデータトランザクションが現在のバージョンが変更されていないことを確認し、新しいバージョンとマニフェストを書き込み、currentVersionIdを更新し、Change.seqとアウトボックスレコードを追加します。コンテンツはメタデータの公開前に完了しているため、可視化されたバージョンが存在しないバイトデータを指すことはありません。失われたレスポンスは同一の冪等性キーで復元されます。
同期には永続カーソルを使用します。通知は名前空間が変更された可能性があることのみを伝えます。デバイスは/changes?cursor=を呼び出し、変更を順番に適用した後にカーソルを進めます。したがって、通知の喪失、重複、順序の入れ替わりによってデータが失われることはありません。30日間の保持ウィンドウより古いカーソルは、整合性のあるスナップショットから再構築し、そのウォーターマークから再開します。2台のデバイスがオフラインで同じバージョンを編集した場合、後からのコミットは新しいバージョンを上書きするのではなく競合コピーを保持します。
キャパシティは論理ストレージで500 PBです。新規または変更されたコンテンツは1日あたり400 TBで、平均約4.6 GB/s、ピーク時は約25 GB/sとなります。1億件のバージョンは平均約1,157コミット/秒、ピーク時は約6,000/秒となります。メタデータは1つのホーム書き込みリージョンを持つ名前空間ごとにシャード化され、ダウンロードはCDNとリージョナルオブジェクトレプリカによってスケールします。
削除時は30日間保持されるトゥームストーンを書き込みます。履歴の有効期限が切れると、ガベージコレクションは保持されているすべてのマニフェストから候補をマークし、猶予期間を待ってから再度照合します。単一の参照カウントがゼロになったという理由だけで削除することはありません。すべてのアップロードおよびコミット境界で障害を注入し、すべての可視バージョンが完全にダウンロードできることを継続的にアサートしながら、通知の喪失、オフライン競合、期限切れカーソル、チェックサム破損、プライマリフェイルオーバー、およびGCの安全性を検証します。」
よくある間違い
- ファイルバイトをメタデータデータベースに保存する → 大容量オブジェクトがレプリケーション、バックアップ、トランザクションの負荷となる → 参照をメタデータに保存し、不変コンテンツはオブジェクトストレージに保存する。
- 最初のパートがアップロードされた後にファイルを公開する → 他のデバイスが不完全なバージョンを読み取る可能性がある → すべてのパートが検証された後にのみメタデータをアトミックにコミットする。
- WebSocket通知を同期の信頼できる情報源として扱う → メッセージの喪失やオフライン期間によって変更を恒久的に見落とす → 通知は信頼できるカーソルプルのトリガーとしてのみ使用する。
baseVersionIdなしでコミットする → オフラインデバイスが無言で新しいバージョンを上書きする → 条件付きコミットを使用し、失敗時は競合コピーを保持する。- 再試行のたびに新しいセッションと冪等性キーを生成する → 重複バージョン、クォータ課金、孤立データが増加する → 安定したキーを使用して元の結果を復元する。
- デフォルトでグローバルなユーザー間インスタントアップロードにする → コンテンツの存在が漏洩し、暗号化と削除が結合してしまう → 重複排除をアカウントまたはテナントにスコープする。
- ユーザー削除直後にチャンクを削除する → オフライン同期、復元、または遅延したトランザクションが存在しないバイトデータを参照してしまう → トゥームストーン、保持期間、猶予期間、および照合を使用する。
- 物理キャパシティに固定の重複排除率を想定する → 未知のワークロードに対して誤った精度を生み出す → 論理容量500 PBを提示し、物理的な削減量は実測値から調整する。
- すべてのファイル変更をすべてのデバイスに確実にプッシュする → 通知コストと再試行状態が爆発する → 名前空間のヒントを統合し、クライアントに差分をプルさせる。
- 最初からアクティブ-アクティブなクロスリージョンメタデータ書き込みを採用する → 名前、移動、現在のバージョンの競合の収束が困難になる → まずは名前空間ごとに1つのホームライターを維持する。
フォローアップの質問と回答
フォローアップ1:固定サイズチャンクとコンテンツ定義チャンク(CDC)をどのように選択しますか?
4 MiB前後のチャンクはシンプルで予測可能であり、追記、局所的な上書き、およびほとんどのメディアファイルに適しています。ユーザーが先頭付近に頻繁にコンテンツを挿入する場合、固定の境界がシフトし、それ以降のすべてのハッシュが変化します。コンテンツ定義チャンク分割は変更されていないコンテンツを再検出できますが、より多くのCPUを消費し、安定してバージョン管理された境界アルゴリズムが必要です。まずは固定チャンクでリリースし、編集後に再利用可能なバイトの割合を測定し、観察された削減効果が複雑さに見合う場合にのみ、選択した大容量ファイルに対してコンテンツ定義チャンク分割を有効にしてください。
フォローアップ2:ディレクトリの移動はどのようにして同期の順序を維持しますか?
移動はメタデータトランザクション内でparentIdを更新し、1つの名前空間シーケンスを追加します。クライアントはseqによってこれを適用します。パスは親の階層から導出されるため、移動によってすべての子孫のパスが書き直されることはありません。名前空間をまたぐ移動は単一のローカルメタデータ更新として装うことはできません。再試行可能なコピー&削除ワークフローとしてモデル化し、進行中の状態をユーザーに明示します。
フォローアップ3:エンドツーエンド暗号化とインスタントアップロードはどのように共存しますか?
クライアント側のエンドツーエンド暗号化では、サーバーは通常暗号文しか見ることができません。ユーザーごとに異なるキーを使用すると、同一の平文から異なる暗号文が生成されるため、ユーザー間の重複排除はほぼ不可能になります。収束暗号(Convergent encryption)はコンテンツ確認攻撃や鍵管理のリスクをもたらします。プロダクトとして選択する必要があります。高プライバシーモードでは重複排除率の低下を受け入れ、テナント管理キーモードではテナント内での重複排除を行うことができます。無条件のグローバルインスタントアップロードと強力なエンドツーエンドの機密性を同時に約束することはできません。
フォローアップ4:1つの巨大な共有ディレクトリがホットになった場合はどうしますか?
まず通知を統合し、一括操作をレート制限し、読み取り専用のディレクトリページをキャッシュし、ボトルネックがシーケンスの割り当て、名前の一意性、一覧取得のどれにあるかを測定します。ファイルメタデータはfileIdによってサブシャード化される場合がありますが、名前空間には依然として順序付けられたウォーターマークが必要です。内部的には、安定した外部カーソルを公開しつつ、シーケンス範囲をバッチで割り当てるか、パーティション化されたログを使用します。単に水平スケールを主張するためだけに、復元可能な順序セマンティクスを破棄してはなりません。
フォローアップ5:ガベージコレクションはどのようにして誤削除を回避しますか?
GCはアクティブな参照カウント単体を信用しません。保持期間内にあるすべてのマニフェストからアクティブセットを構築し、そのセット外のチャンクを候補としてマークし、最大トランザクション遅延、レプリケーション遅延、および復元遅延よりも長い時間待機してから、削除前に現在のマニフェストと照合します。削除は冪等であり監査ログが残されます。マニフェストの欠落や不一致がある場合、回収は延期されます。未完了のマルチパートのパートも、独立したセッション期限切れおよび中止処理が必要です。
フォローアップ6:クロスリージョンのディザスタリカバリをどのように提供しますか?
各名前空間は通常、メタデータの書き込みを受け付ける1つのホームリージョンを持ちます。他のリージョンはそのログとオブジェクトを非同期にレプリケーションします。フェイルオーバー時は、まず古いライターをフェンシング(隔離)し、新しいエポックのもとで復旧レプリカを昇格させ、ルーティングを変更します。RPOはレプリケーションラグに依存し、RTOは検出と昇格の時間に依存します。RPOをゼロにするには、同期的なクロスリージョンクォーラムとより高い書き込みレイテンシが必要です。復旧した古いプライマリは、書き込みを受け付ける前に名前空間のリーダーシップエポックを検証する必要があります。
フォローアップ7:同期がデータを決して見落とさないことをどのように証明しますか?
アップロード、コミット、移動、削除、競合、再試行のシーケンスを生成する状態モデルを構築します。シーケンスNを適用した後のクライアントの状態が、Nにおけるサーバーのスナップショットと等しいことをアサートします。エンドツーエンドテストでは、チェンジログを破損させることなく通知をランダムにドロップ、重複、順序変更し、デバイスがカーソルプルを通じて依然として収束することを確認します。変更を適用した後かつカーソルを保存する前、およびローカルコンテンツを保存した後かつプロセス完了前にクラッシュを注入します。リプレイは冪等であり続けなければならず、すべてのデバイスが最終的に同じブラウズ可能なバージョンツリー(バージョン検証グラフ)に到達しなければなりません。