回答A: OpenAI GPT-5.2
A) API 設計
- 短縮URLの作成
- エンドポイント: POST /v1/urls
- リクエストJSON:
- long_url (文字列、必須、最大例: 8KB)
- custom_alias (文字列、任意; 提供される場合は一意であり、許可された文字セット/長さを満たす必要があります)
- expire_at (タイムスタンプ、任意)
- metadata (オブジェクト、任意: 例: キャンペーン、user_id)
- レスポンス (201):
- code (文字列)
- short_url (文字列)
- long_url (文字列)
- created_at (タイムスタンプ)
- expire_at (タイムスタンプ|null)
- エラー:
- 400 無効なURL/エイリアス
- 409 エイリアスが既に存在します
- 429 レート制限
- 解決/リダイレクト
- エンドポイント: GET /{co...
全文を表示 ▼
A) API 設計
- 短縮URLの作成
- エンドポイント: POST /v1/urls
- リクエストJSON:
- long_url (文字列、必須、最大例: 8KB)
- custom_alias (文字列、任意; 提供される場合は一意であり、許可された文字セット/長さを満たす必要があります)
- expire_at (タイムスタンプ、任意)
- metadata (オブジェクト、任意: 例: キャンペーン、user_id)
- レスポンス (201):
- code (文字列)
- short_url (文字列)
- long_url (文字列)
- created_at (タイムスタンプ)
- expire_at (タイムスタンプ|null)
- エラー:
- 400 無効なURL/エイリアス
- 409 エイリアスが既に存在します
- 429 レート制限
- 解決/リダイレクト
- エンドポイント: GET /{code}
- 動作:
- デフォルトで301 Moved Permanently (またはトラッキング/実験が必要な場合は302)
- Locationヘッダー = long_url
- オプション: GET /v1/urls/{code} はリダイレクトの代わりにJSONを返します (APIクライアント用)
- エラー:
- 404 見つかりません/期限切れ
- 削除/無効化 (任意、不正利用/ユーザー制御用)
- エンドポイント: DELETE /v1/urls/{code}
- 認証必須
- レスポンス: 204
- 分析 (任意、非同期/近似可能)
- エンドポイント: GET /v1/urls/{code}/stats?from=&to=
- 集計されたカウンター (日別クリック数、参照元、ジオグラフィックなど) を返します
注記:
- 認証: 作成および管理にはAPIキー/OAuthを使用します。リダイレクトは公開のままです。
- Idempotency: POSTリクエストでIdempotency-Keyヘッダーをサポートし、リトライ時の重複を防ぎます。
B) データモデルとストレージ
ワークロード
- 書き込み: 1ヶ月あたり1億件 ≈ 1日あたり333万件 ≈ 平均38.6書き込み/秒 (ピークはより高い)。
- 読み取り: 100:1 => 1ヶ月あたり100億リダイレクト ≈ 平均3.86K読み取り/秒 (ピークははるかに高い)。
ストレージの選択
- プライマリストア: 非常に高い読み取りQPS、低レイテンシ、水平スケーリング、マルチDCレプリケーションに最適化された分散キーバリューストア/ワイドカラムストア (例: DynamoDB/Cassandra/ScyllaDB)。
- 理由: アクセスパターンは主に短いコードによるキー検索です。値は小さく、高可用性と予測可能なレイテンシが強く求められます。
- セカンダリシステム:
- キャッシュ: リージョンごとのRedis/Memcachedクラスタ。
- 分析パイプライン: Kafka/PubSub + ストリーム処理 + OLAPストア (クリティカルパスではありません)。
スキーマ
- url_mapping (プライマリ)
- パーティションキー: code (文字列)
- カラム:
- long_url (文字列)
- created_at (タイムスタンプ)
- expire_at (タイムスタンプ|null)
- user_id (文字列|null)
- status (active/deleted)
- checksum (整合性のため、任意)
- TTL: expire_atが設定されている場合、ネイティブTTLを使用し、期限切れのエントリを自動削除します。
- alias_reservation (カスタムエイリアスの一意性をサポートする場合、任意)
- キー: custom_alias
- 値: code / 所有権メタデータ
- idempotency (任意)
- キー: (user_id, idempotency_key)
- 値: code
- TTL: 例: 24時間
ストレージ見積もり (10年間)
- 10年間の新規URL数: 1億件/月 * 12ヶ月 * 10年 = 120億件のマッピング。
- レコードあたりのサイズ概算:
- code: 約8バイト (または最大約10文字)
- long_url: 平均200バイトと仮定 (保守的)、オーバーヘッドを追加。
- メタデータ/カラム/インデックスオーバーヘッド: ストアによって約100〜200バイトと仮定。
- 合計実効サイズ (まだカウントされていないレプリケーションオーバーヘッドを含む): レコードあたり約400バイト (妥当な計画値)。
- 生データ: 120億 * 400バイト = 4.8TB。
- ストレージエンジンオーバーヘッド + コンパクション + セカンダリインデックスを含む: 約2〜3倍を計画 => 約10〜15TB。
- レプリケーション:
- リージョン内 (RF=3): 約30〜45TB。
- マルチリージョン (例: 2つのアクティブ-アクティブリージョン): 倍増 => 全リージョンで合計約60〜90TB。
(これらは計画値であり、正確な値は平均URL長とDBオーバーヘッドによって異なります。)
C) 短縮URL生成
目標
- できるだけ短く
- 高スケールでの衝突フリー
- 少なくとも10年間の成長をサポート
キー空間の計算
- 10年間で必要なコードの総数: 120億。
- Base62文字セットを使用: [0-9][a-z][A-Z] => 62シンボル。
- 長さLの容量: 62^L。
- 62^6 ≈ 56.8B (120億には十分)
- 62^7 ≈ 3.52T (より多くのヘッドルーム)
選択肢
- 最小長6文字の可変長を使用。
- 最初の約568億コードには6文字から開始。これは既に10年間の要件を大幅なマージン (56.8B/12B ≈ 4.7倍) でカバーしています。
- 既存のリンクを壊すことなく、将来的に7文字に移行できる能力を維持します。
生成アルゴリズム (衝突なし)
選択されたオプション: グローバルに一意な数値ID + Base62エンコーディング。
- 単調増加する64ビットID空間を維持します。
- IDをBase62にエンコードしてコードを生成します。
- 衝突回避: IDは構築上一意であるため、不要です。
スケールでのID生成方法
- Snowflakeのような分散IDアロケータ、または範囲リースを持つ中央「IDサービス」を使用します:
- IDサービスは、各リージョンで一貫性の高いストア (例: etcd/Spanner) にカウンタを格納します。
- 各アプリサーバーは、ローカルで生成するためにIDブロック (例: 100万ID) をリースします。
- ブロックが枯渇したら、新しいブロックを要求します。
- これにより、書き込みごとの競合を回避しつつ、一意性を確保します。
カスタムエイリアスの処理
- custom_aliasが提供された場合:
- 文字セット/長さを検証します。
- url_mappingに対する条件付き書き込み (比較・交換) で、キー=aliasとします。存在する場合は409を返します。
D) スケーリングとパフォーマンス
高レベルアーキテクチャ
- Anycast/GeoDNS -> グローバルロードバランサー -> リージョンL7ロードバランサー -> ステートレスAPI/リダイレクトサーバー。
- 分離されたサービス:
- 書き込みパス: URL作成サービス
- 読み取りパス: リダイレクトサービス
- 共有ストレージ + キャッシュ
読み取りと書き込みのスケーリングを独立して行う
- リダイレクトサービスは、QPS/レイテンシに基づいて水平スケーリングされます (おそらく主要なコスト)。
- 作成サービスは、書き込みスループットに基づいてスケーリングされます。
- 別々の自動スケーリンググループと独立したデプロイパイプラインを使用します。
データパーティショニング
- DBノード全体でコードハッシュ (またはコード自体) によってパーティショニングします。
- コードはBase62エンコード時にID空間全体で実質的に均一であるため、均一な分散が可能です。
キャッシング戦略
- プライマリ: リダイレクト用のCDN/エッジキャッシュ + リージョン内インメモリキャッシュ。
- CDN:
- パス (コード) をキーとして301/302レスポンスをTTL付き (例: 5〜60分、またはexpire_atを尊重) でキャッシュします。
- 非常にホットなリンクの場合、CDNはグローバルにほとんどのトラフィックを吸収できます。
- リージョン内キャッシュ (Redis/Memcached):
- キー: code
- 値: long_url + expire_at + status
- TTL: min(default_ttl, expire_at-now)
- Eviction: LRUまたはLFU (人気が偏っている場合はLFUを推奨)。
- CDN:
期待されるヒット率
- URLアクセスは通常非常に偏っています (Zipf分布)。CDN + リージョン内キャッシュにより、リダイレクトで95〜99%のヒット率が可能です。90%でも役立ちます。
- キャッシュウォーミング: 書き込み時にマッピングをキャッシュにプッシュします。また、無効なコードに対する繰り返しDBヒットを減らすために、ミスに対するネガティブキャッシング (短いTTL) も行います。
<50msのp95リダイレクトレイテンシの達成
- キャッシュヒットのクリティカルパス:
- エッジ/CDNヒット: 多くの場合 <20ms。
- リージョン内キャッシュヒット: LB + アプリ + Redisルックアップ + レスポンス: リージョン内では通常5〜15ms。
- キャッシュミスの場合:
- ローカルリージョンのDBからの単一DB読み取り: 目標5〜20ms。
- リダイレクトサーバーをユーザーの近くに配置します (マルチリージョン + エッジ経由)。
- キープアライブ、コンポーネント間のHTTP/2、Redis/DBへの接続プーリングを使用します。
- 同期分析を避け、クリックイベントをキューに非同期で発行します。
書き込みパフォーマンス
- 書き込みは読み取りに比べて少ないですが、バーストにも対応します。
- 書き込みフロー:
- ID/コードを生成します。
- DBに書き込みます (リージョン内のクォーラム/マジョリティ)。
- キャッシュにライトスルーします。
- レスポンスを返します。
- オプション: ハッシュ->コードインデックスを格納して、同一のlong_urlを重複排除します (トレードオフ。Fを参照)。
E) 信頼性と耐障害性
可用性目標: 99.9%
- すべての状態を持つコンポーネントについて、各リージョン内でマルチAZ。
- リダイレクトトラフィックのために、少なくとも2つのリージョンでアクティブ-アクティブ。
レプリケーション戦略
- リージョン内: AZをまたいだレプリケーションファクター3。
- クロスリージョン:
- url_mappingの非同期レプリケーションにより、書き込みレイテンシを低く保ち、可用性を高くします。
- リダイレクトはローカルリージョンから提供されます。レプリケーションラグによりローカルマッピングが見つからない場合、別のリージョンにフォールバックします (下記参照)。
データセンター/リージョン障害時の処理 (正常な劣化)
- グローバルロードバランサーのヘルスチェックを使用します:
- リージョンが非健康的であれば、トラフィックを次に近い健康なリージョンにルーティングします。
- リダイレクトリクエストの場合:
- リージョン内キャッシュ/DBに障害が発生した場合、リダイレクトサービスは以下を実行できます:
- キャッシュを試す
- ローカルDBを試す
- ローカルDBが利用できない場合、リモートリージョンの読み取りエンドポイントをクエリする (厳密なタイムアウト付き) か、クロスリージョン読み取りレプリカを使用します。
- すべて失敗した場合、Retry-After付きの高速な503を返します (正常な障害)。
- リージョン内キャッシュ/DBに障害が発生した場合、リダイレクトサービスは以下を実行できます:
- 書き込みリクエストの場合:
- ローカルリージョンでの書き込みを優先します。リージョンがダウンしている場合は、別のリージョンにフェイルオーバーします。
- ID割り当て: 各リージョンは、フェイルオーバー中の競合を回避するために、独自のIDブロック名前空間 (またはSnowflakeのリージョンビットを使用) を持ちます。
CAP定理のトレードオフ
- グローバル操作については、強力な一貫性よりも可用性を選択します:
- リダイレクトは非常に利用可能である必要があり、古い読み取りは短時間なら許容されます。
- クロスリージョンレプリケーションは非同期です。新しく作成された短縮URLは、短い期間、別のリージョンで解決できない可能性があります。
緩和策: - 作成後、同じリージョンドメインでホストされる短縮URLを返します (または、最初の数分間はオリジンリージョンにルーティングするエッジを使用します)。
- 作成時に、オプションで2つのリージョンに同期書き込みを行います (プレミアム/エンタープライズティアの場合、レイテンシ/コストが高くなります)。
バックアップと災害復旧
- オブジェクトストレージへの定期的なスナップショットと増分バックアップ。
- 定期的なリストア訓練。
F) トレードオフの議論
- IDベースのコード生成 vs ランダムトークン
- 選択: IDベース (範囲リース/Snowflake) + Base62。
- 利点:
- 衝突なし、リトライループの必要なし。
- 予測可能なキャパシティプランニングとシンプルなDB制約。
- 高速な書き込み。
- 犠牲:
- コードは推測可能/シーケンシャルです (セキュリティによる秘匿性は提供されません)。
緩和策: - 数値IDに対するオプションの「ソルト付き順列」(例: Feistelネットワーク) を追加して、一意性を維持しながらコードを非シーケンシャルにします。
- コードは推測可能/シーケンシャルです (セキュリティによる秘匿性は提供されません)。
- 非同期クロスリージョンレプリケーション (AP) vs 同期マルチリージョン (CP)
- 選択: 非同期クロスリージョンレプリケーション。
- 利点:
- 低い書き込みレイテンシ、部分的な障害時の高い可用性。
- リージョンに障害が発生した場合でも、リダイレクトを提供し続ける能力が高い。
- 犠牲:
- 結果整合性: 新しく作成されたURLが別のリージョンで読み取れない短い期間が存在する可能性があります。
緩和策: - 読み取り修復/オリジンリージョンへのフォールバックで最新リンクに対応。高SLA顧客向けのオプションのデュアル書き込み。
- 結果整合性: 新しく作成されたURLが別のリージョンで読み取れない短い期間が存在する可能性があります。
- 重いキャッシング/CDN vs 常にDBにヒット
- 選択: CDN + リージョン内キャッシュ。
- 利点:
- <50msのp95を容易に満たし、DB負荷を劇的に削減します。
- バイラルリンクのトラフィックスパイクに対応します。
- 犠牲:
- キャッシュ無効化の複雑さ (例: 削除/期限切れリンク)。
緩和策: - 短いTTL、expire_atの尊重、CDNでの削除時の明示的なパージ (サポートされている場合)。ステータスフラグとネガティブキャッシングを慎重に使用します。
- キャッシュ無効化の複雑さ (例: 削除/期限切れリンク)。
判定
勝利票
3 / 3
平均スコア
総合点
総評
回答Aは、6つのセクションすべてを実質的な深さで網羅した、包括的で詳細なシステム設計です。QPS計算、レプリケーションファクターを含むストレージ見積もり、キャッシュヒット率などの正確な定量的推論を随所に示し、冪等性、ネガティブキャッシュ、不正利用対策などのエッジケースにも対処しています。また、コネクションプーリング、HTTP/2、コード難読化のためのFeistelネットワーク、ライトスルーキャッシュなどの実践的なエンジニアリングの詳細も提供しています。API設計には、レート制限、冪等性ヘッダー、分析エンドポイントが含まれます。ストレージ見積もりは、リージョン間のレプリケーションを考慮しています。トレードオフのセクションでは、明確な緩和策を伴う3つの実際のトレードオフを特定しています。信頼性のセクションでは、劣化したシナリオのための詳細なフォールバックチェーンを提供しています。全体として、シニアレベルのエンジニアリングの深さと実践的な認識を示しています。
採点詳細を表示 ▼
設計の質
重み 30%回答Aは、明示的なQPS計算(書き込み/秒38.6、読み取り/秒3.86K)、マルチレイヤーキャッシュ(CDN + リージョンRedis/Memcached)、詳細な書き込みおよび読み取りパス、コネクションプーリング、HTTP/2最適化、Kafka経由の非同期分析、および範囲リースを備えた適切に設計されたID割り当てシステムを備えた、徹底的なアーキテクチャを提供します。アーキテクチャの選択は適切に正当化され、制約と関連付けられています。
完全性
重み 20%回答Aは、6つのセクションすべてを実質的な詳細で網羅しています。追加のエンドポイント(DELETE、分析)、冪等性サポート、ネガティブキャッシュ、エイリアス予約スキーマ、リージョン全体でのレプリケーションファクターを含む詳細なストレージ見積もり(合計60〜90TB)、および緩和策を伴う3つのトレードオフが含まれています。ストレージ見積もりは、オーバーヘッドとマルチリージョンレプリケーションを現実的に考慮しています。
トレードオフの説明力
重み 20%回答Aは、3つの実際のトレードオフを特定しています:IDベース対ランダムトークン、非同期対同期クロスリージョンレプリケーション、およびヘビーキャッシュ対常にDBヒット。各トレードオフには、明確な利点、犠牲、および実践的な緩和策(コード難読化のためのFeistelネットワーク、レプリケーションラグのためのリードリペア、キャッシュ無効化のための短いTTL)が含まれています。この推論は、エンジニアリングのトレードオフに関する深い理解を示しています。
拡張性・信頼性
重み 20%回答Aは、劣化したシナリオ(キャッシュ -> ローカルDB -> リモートリージョン -> Retry-After付き503)のための詳細なフォールバックチェーン、フェイルオーバー中の競合を回避するためのリージョン認識ID割り当て、明示的なレイテンシの内訳(キャッシュあり/なしパス)、およびリージョン内(RF=3)とクロスリージョンレプリケーションの両方について説明しています。キャッシュ戦略と50ms p95ターゲット間の関連性は明確で説得力があります。
分かりやすさ
重み 10%回答Aは、明確なセクションヘッダー、サブセクション、および箇条書きでよく整理されています。メモ、番号付きリスト、明示的なラベルの使用により、フォローしやすくなっています。定量的推論は明確に提示されています。一部のセクションは密ですが、読みやすいままです。
総合点
総評
回答Aは、傑出した専門家レベルのシステム設計を提供しています。分散KVS(Key-Value Store)という非常に適切な技術スタックを選択し、詳細かつ現実的なストレージ計算を行い、CDN/エッジキャッシュ、マルチリージョンアクティブアクティブデプロイメント、明確な段階的劣化パスを含む洗練されたスケーリングおよび信頼性戦略を概説することで、分散システム原則に対する深い理解を示しています。API設計は包括的であり、トレードオフに関する議論はニュアンスに富み、洞察に満ちています。すべてのセクションにわたる詳細レベルは並外れています。
採点詳細を表示 ▼
設計の質
重み 30%アーキテクチャはこの問題に例外的に適しています。DynamoDB/Cassandraのような分散キーバリューストアの選択は、高読み取り、キー検索ワークロードに最適です。Anycast/GeoDNSから分離された読み取り/書き込みサービスに至るまで、全体的な設計は堅牢でスケーラブルであり、専門家レベルの思考を示しています。
完全性
重み 20%回答は非常に包括的で、6つのセクションすべてに詳細に対処しています。API設計は特に徹底しており、分析や削除のためのオプションですが重要なエンドポイント、および冪等性や認証に関する考慮事項も含まれています。
トレードオフの説明力
重み 20%回答は、3つの明確で非常に適切なトレードオフを提供しています。その理由は優れており、何が得られ、何を犠牲にするかを明確に概説しており、さらに重要なことに、各選択肢の欠点の実際的な緩和策も含まれています。これは、エンジニアリングのトレードオフに対する成熟した理解を示しています。
拡張性・信頼性
重み 20%これは傑出したセクションです。読み取りと書き込みのスケーリングを個別に計画する手順は明確です。キャッシュ戦略はマルチレイヤー(CDN + リージョンキャッシュ)であり、グローバル規模でレイテンシ目標を満たすために不可欠です。信頼性計画も優れており、詳細な段階的劣化パスと、CAP定理における明確で十分に緩和されたAP選択が含まれています。
分かりやすさ
重み 10%回答は例外的に明瞭で、構成も優れています。要求されたA-F形式に完全に準拠しており、見出し、サブ箇条書き、簡潔な言葉遣いを使用して、複雑なアイデアを消化しやすい方法で提示しています。
総合点
総評
回答Aは、API、データモデル、容量の見積もり、キャッシュ、マルチリージョンフェイルオーバー、レイテンシ制御のための現実的なアーキテクチャなど、必須セクションAからFまですべてを網羅した、強力で構造化されたシステム設計です。ワークロードに直接選択肢を結びつけ、冪等性、ネガティブキャッシュ、CDNの動作、クォーラム/レンジリースID生成、および段階的な劣化パスなどの運用上の詳細を含んでいます。マイナーな弱点としては、一部の見積もりがまだ粗く、いくつかの実装の選択肢が単一の明確にコミットされた設計ではなく、オプションとして提示されている点が挙げられます。
採点詳細を表示 ▼
設計の質
重み 30%ステートレスな読み書きサービス、分散KVストア、リージョナルキャッシュとCDN、非同期分析、マルチリージョンルーティング、および具体的なID生成戦略など、ワークロードに合わせた一貫したエンドツーエンドのアーキテクチャを使用しています。設計は、懸念事項の分離と実践的な実装の詳細をうまく示しています。
完全性
重み 20%6つの必須セクションすべてを実質的に扱い、認証、冪等性、オプションの分析、エイリアス予約、バックアップ戦略、段階的な劣化ステップなどの有用な詳細を追加しています。定量的推論は複数のセクションに含まれています。
トレードオフの説明力
重み 20%IDベースの生成対ランダムトークン、非同期レプリケーション対同期レプリケーション、キャッシュの複雑さ対レイテンシなど、明示的な利点、犠牲、緩和策を伴う複数の意味のあるトレードオフを特定しています。推論はワークロードとSLA要件に結び付けられています。
拡張性・信頼性
重み 20%水平スケーリング、パーティショニング、読み書き分離、期待されるキャッシュヒット率、CDNサポート、p95レイテンシパス、RF=3、マルチAZおよびアクティブ-アクティブリージョン設定、非同期クロスリージョンレプリケーション、およびリージョン障害時のフォールバック動作について強力に扱っています。具体的なリクエストフローで段階的な劣化を明示的に扱っています。
分かりやすさ
重み 10%非常に読みやすく、AからFまで論理的に整理されており、理解しやすいです。箇条書き、数式、段階的なフローの使用は理解を助けますが、回答はやや密度が高いです。