プロンプトとコンテキスト
このバックエンドの質問では、HTTPの部分レスポンス、オブジェクトストレージの読み取り、およびダウンロードの状態遷移機械(ステートマシン)についてテストします。課題は単にヘッダーをストレージに転送することではありません。障害やリトライが発生しても、範囲、エンティティのバージョン、エンコーディング、権限、および並行セグメントの一貫性を維持することにあります。
面接官が評価するポイント
- 1つのバイト範囲をパースし、206、Content-Range、Content-Length、Accept-Rangesを正しく構築できるか。
- ETagまたはLast-ModifiedとIf-Rangeを組み合わせることで、クライアントが異なるファイルバージョンを結合してしまうのを防げるか。
- 無効な範囲、期限切れの署名、削除されたオブジェクト、レート制限、およびマルチレンジのコストが処理されているか。
- 整合性、可観測性、および認可によって、エンドポイントが任意のオブジェクトリーダー(不正な読み取り口)になるのを防げているか。
確認すべき質問
オブジェクトが公開されているか、最大サイズ、マルチレンジレスポンスが必要か、ストレージがネイティブで範囲指定をサポートしているか、圧縮が許可されているか、クライアントがETagを保持するかを確認します。また、URLの有効期限、セグメントの並行性、整合性アルゴリズム、およびリソースバージョンが変更された場合のプロダクトの挙動について尋ねます。
30秒の回答フレームワーク
リクエストを認可してオブジェクトバージョンを固定し、サイズ、ETag、メディアメタデータを読み取ります。Rangeがない場合は200を返し、満たせる範囲が1つの場合は正確なContent-Rangeとともに206を返し、不正な形式または満たせない範囲の場合は現在の長さとともに416を返します。If-Rangeの不一致が発生した場合は現在のバージョンの完全なレスポンスを返し、クライアントに最初から再開させます。各セグメントはレートと並行性が制限され、レスポンスと最終ファイルの両方がバージョンおよびチェックサムに対して検証されます。
ステップバイステップの詳細解説
1. 表現と認可の境界を固定する
ユーザー、テナント、オブジェクトIDによって認可を行い、クライアントの任意のパスをストレージキーに直接マッピングすることは絶対に避けます。オブジェクトのメタデータを読み取り、バージョン識別子、合計バイト数、Content-Type、Content-Encoding、およびETagを固定します。オブジェクトが変更される可能性がある場合は、1回のダウンロード中にメタデータとバイトデータが乖離しないよう、不変ストレージまたはバージョニングされたストレージを使用します。
2. 範囲をパースしてレスポンスを構築する
bytes=start-end、bytes=start-、またはbytes=-suffixのいずれか1つの範囲をサポートし、整数、オーバーフロー、合計長を検証します。満たせる範囲を表現に合わせてクランプした後、206、Content-Range、および正確な長さを返します。Rangeがない場合は200を返します。満たせる範囲がない場合は、Content-Range: bytes */totalとともに416を返します。マルチレンジリクエストには明確な選択が必要です。拒否するか、制限されたリクエストに分割するか、multipartを実装するかであり、最初の部分だけを暗黙的に返してはなりません。
3. If-Rangeとコンテンツコーディングを処理する
If-Range内の強いETagまたは日付は、選択された表現と依然として一致する場合にのみ適用し、一致しない場合はRangeを無視して現在の完全な表現を送信します。範囲は、実際に転送される表現のバイトを指します。圧縮されたバイトをスライスして、クライアントに非圧縮ファイルであるかのように結合させてはなりません。動的圧縮を無効にするか、エンコーディングごとに独立したバージョンとチェックサムを割り当てます。
4. 並行性、コスト、およびリカバリを制限する
多数の極小リクエストによるストレージコストの増大を防ぐため、ユーザー、テナント、オブジェクトごとのセグメント数に加え、総帯域幅と最小範囲サイズを制限します。失敗したセグメントは、同じバージョンと範囲でのみリトライします。署名付きURLの期限が切れた場合は、バージョンを変更せずに新しいURLを発行します。オブジェクトの削除や権限の変更があった場合は以降のセグメントを停止し、クライアントは不完全なファイルを暗黙的に結合せず破棄します。
5. 整合性を検証し挙動を監視する
ダウンロード完了後、オブジェクトバージョン、合計長、チェックサムを検証します。リスクの高いデータについては、結合前に各セグメントを検証します。ダウンロード認証情報をログに記録することなく、正規化された範囲、バージョン、ステータス、バイト数、ストレージレイテンシ、キャッシュヒット、リトライ回数をログに記録します。空の範囲、サフィックス、オーバーフロー、オブジェクトの更新、並行リトライ、オフライン再開、各Content-Encodingをテストし、206が誤ったバージョンを提供しないことを証明します。
優れた回答例
認可後、不変なオブジェクトバージョンを固定し、そのサイズ、ETag、タイプ、エンコーディングを公開します。満たせる単一のbytes範囲に対してはContent-RangeおよびContent-Lengthとともに206を返し、範囲がない場合は200を返し、満たせない範囲にはbytes */totalとともに416を返します。If-Rangeが一致しない場合はRangeを無視して現在の完全なバージョンを送信し、ファイルが混ざるのを防ぎます。ユーザーごとおよびオブジェクトごとの並行性、レート、最小範囲の制限によりコストを抑え、リトライ時も同じバージョンを維持します。クライアントは長さ、バージョン、チェックサムを検証し、サーバーは範囲、ステータス、ストレージレイテンシ、リトライを監視します。
よくある間違い
- 認可、オブジェクトバージョン、または整数のオーバーフローを確認せずにRangeを転送する。
- 満たせない範囲に対して416ではなく200や空のボディを返す。
- If-Rangeを無視し、更新によってバージョンが混ざったファイルを作成させてしまう。
- クライアントが後で非圧縮として扱う圧縮バイトに対して範囲座標を適用する。
- 無制限の極小セグメントや並行性を許可し、1つのダウンロードをストレージへの負荷集中(ストーム)に変えてしまう。
- 合計長、ETag、最終チェックサムではなく、ステータスコードのみをチェックする。
フォローアップの質問と回答
なぜ常に206を返してはいけないのですか?
Rangeがない場合、クライアントは完全な表現を要求しているため、200が正解です。Rangeがある場合でも、サーバーは充足可能性を確認する必要があり、416はクライアントがリクエストを修正できるように現在の長さを伝えます。
If-RangeはIf-Matchとどのように異なりますか?
If-Rangeは部分転送を続行できるかどうかを決定します。一致すれば206になり、不一致なら完全な表現が返されます。If-Matchは対象の操作を実行するための事前条件であるため、失敗した場合の意味合いが異なります。
マルチレンジリクエストはどのように処理すべきですか?
まず、クライアントとストレージがそれを必要としているかを確認します。制限されたリクエストに分割するか、multipart/byterangesを実装します。コストが見合わない場合は、最初の範囲だけを返して曖昧さを生むのではなく、明示的に拒否します。
署名付きダウンロードリンクの悪用をどのように防ぎますか?
ユーザー、テナント、オブジェクト、バージョン、権限にバインドされた有効期間の短い署名を使用します。サーバー側で境界を再チェックし、並行性、レート、範囲数、総バイト数を制限します。アクセス権の取り消しや削除が発生した場合は、後続の範囲リクエストを無効化する必要があります。