URL短縮サービス — ハイレベル設計 機能要件 ユーザーは長いURLを送信し、一意の短いコード(例:https://short.ly/aB3xYz)を受け取ることができます。短いURLにアクセスすると、ブラウザは元の宛先にリダイレクトされます。短いリンクは、設定可能なTTL後にオプションで有効期限が切れます。ユーザーはオプションでカスタムエイリアスを要求できます。基本的なクリックカウンターがリンクごとに維持されます。 非機能要件 システムは、月間約2000万件の書き込みと2億件の読み取りを処理する必要があります。これは、平均で約8件の書き込み/秒と80件の読み取り/秒に相当し、ピーク時はその数倍になります。リダイレクトのレイテンシは、95パーセンタイルで50ミリ秒...
全文を表示 ▼
URL短縮サービス — ハイレベル設計 機能要件 ユーザーは長いURLを送信し、一意の短いコード(例:https://short.ly/aB3xYz)を受け取ることができます。短いURLにアクセスすると、ブラウザは元の宛先にリダイレクトされます。短いリンクは、設定可能なTTL後にオプションで有効期限が切れます。ユーザーはオプションでカスタムエイリアスを要求できます。基本的なクリックカウンターがリンクごとに維持されます。 非機能要件 システムは、月間約2000万件の書き込みと2億件の読み取りを処理する必要があります。これは、平均で約8件の書き込み/秒と80件の読み取り/秒に相当し、ピーク時はその数倍になります。リダイレクトのレイテンシは、95パーセンタイルで50ミリ秒未満である必要があります。サービスは非常に利用可能である必要があります(目標稼働率99.9%)。短いコードはグローバルに一意である必要があります。システムは水平スケーリング可能であり、単一ノードの障害を正常に許容する必要があります。 APIエンドポイント POST /api/links: JSONボディ(フィールド:longUrl(必須)、customAlias(オプション)、ttlDays(オプション))を受け付けます。shortCodeとshortUrlを含むJSONレスポンスを返します。これは書き込みパスです。 GET /{shortCode}: リダイレクトエンドポイントです。サーバーはコードを検索し、元のURLに対してHTTP 301(永続)または302(一時、分析に推奨)で応答します。 GET /api/links/{shortCode}: メタデータ(元のURL、作成時間、有効期限、クリック数)を返します。 DELETE /api/links/{shortCode}: リンクを削除済みとしてマークします(ソフト削除)。 データモデル コアデータを保持する単一のプライマリテーブル、linksがあります。主要な列:short_code(varchar、主キー)、long_url(text、not null)、created_at(timestamp)、expires_at(timestamp、nullable)、is_deleted(boolean、デフォルトfalse)、click_count(integer、デフォルト0)、owner_id(varchar、匿名リンクの場合はnullable)。expires_atのインデックスは、効率的な有効期限スイープをサポートします。カスタムエイリアスがサポートされている場合、short_codeは一意性チェック後にユーザー提供の値に設定されるだけです。 ショートコード生成 デフォルトのアプローチは、一意の整数IDのbase-62エンコーディング(文字a-z、A-Z、0-9)を使用します。7文字のbase-62コードは、62^7 ≈ 3.5兆の可能なコードを提供し、予見可能な需要をはるかに超えています。整数IDは、Snowflakeスタイルのサービスやデータベースシーケンスなどの分散IDジェネレーターによって生成されます。これにより、アプリケーションレイヤーでの調整オーバーヘッドなしに一意性が保証されます。書き込み時に、アプリケーションは生成されたIDをエンコードしてショートコードを生成し、両方を保存します。カスタムエイリアスの場合は、アプリケーションは挿入前にそのshort_codeを持つ既存の行をチェックします。取得済みの場合、呼び出し元に競合エラーを返します。 読み取りおよび書き込みフロー 書き込みパス:クライアントはAPIサービスにPOSTします。サービスはURLを検証します(基本的な形式チェック、オプションのブロックリストチェック)。IDジェネレーターから新しい一意のIDを取得し、それをショートコードにエンコードして、プライマリデータベースに1行挿入します。新しいマッピングは、オプションでキャッシュに事前ウォームされます。ショートURLがクライアントに返されます。 読み取りパス:クライアントはGET /{shortCode}を発行します。APIサービスはまず分散キャッシュ(Redis)をチェックします。キャッシュヒットの場合、すぐに302リダイレクトを返し、非同期でクリックカウンターをインクリメントします。キャッシュミスの場合、プライマリデータベースにクエリを実行し、結果をTTL(例:24時間)付きでキャッシュに書き込み、その後リダイレクトします。コードが見つからない、期限切れ、または削除されている場合は、404を返します。 ストレージとキャッシング プライマリストレージは、強力な一貫性、ACID保証、および簡単な一意キー強制のためのリレーショナルデータベース(PostgreSQLまたはMySQL)です。月間2000万件のリンクと控えめな行サイズ(約500バイト)で、1年間のデータは約120 GBとなり、単一のプライマリとリードレプリカで容易に管理できます。書き込みパスのために、プライマリデータベースの前に分散インメモリキャッシュ(Redis)が配置されます。少数のリンクがほとんどのトラフィックを占める(べき乗則分布)ことを考えると、LRU(Least Recently Used)エビクションポリシーと24時間のTTLを持つキャッシュは、控えめなメモリで高いヒット率を達成するでしょう。約200バイトのホットリンク1000万件を想定すると、キャッシュメモリは約2 GBで済みます。クリック数はRedis(INCR)でバッファリングされ、書き込み増幅を回避するために定期的にデータベースにフラッシュされます。 大量の読み取りトラフィックのスケーリング API層はステートレスであり、ロードバランサーの後ろで水平にスケールします。データベースのリードレプリカは、キャッシュミスによる読み取りクエリを吸収します。キャッシュクラスター(Redis Cluster)はshort_codeでシャーディングできます。CDNをリダイレクトエンドポイントの前に配置して、最も人気のあるリンクを提供できます。これにより、オリジンに一切ヒットすることなく、エッジノードから302レスポンスを提供できます。ブラウザはデフォルトで302レスポンスをキャッシュしないため、CDNは効果的であるために短時間(例:60秒)キャッシュするように設定する必要があります。 期限切れまたは削除されたリンクの処理 期限切れは読み取り時にチェックされます。expires_atが過去であるか、is_deletedがtrueの場合、サービスは404を返し、エントリをキャッシュから削除します。バックグラウンドジョブが定期的に(例:夜間)実行され、expires_atが経過した行をハード削除またはアーカイブし、アクティブなデータセットを小さく保ち、インデックススキャンを高速に保ちます。ソフト削除(is_deletedフラグ)は、監査証跡と、永久削除前の回復の可能性を可能にします。 不正利用防止とレート制限 レート制限は、IPアドレス、および認証済みユーザーの場合はユーザーIDをキーとするトークンバケットまたはスライディングウィンドウアルゴリズムを使用してAPIゲートウェイレイヤーで実施されます。合理的なデフォルト:匿名ユーザーの場合はIPあたり1分あたり10件の書き込み、認証済みアカウントの場合はより高い制限。書き込みパスでは、送信されたURLは、既知の悪意のあるまたはフィッシングドメインのブロックリスト(Redisセットまたは小さなインメモリtrieとして維持)に対してチェックされます。CAPTCHAまたは電子メール検証は、バルクまたは疑わしい送信パターンに対して要求される場合があります。異常に急増した404レスポンス(例:列挙攻撃)を受信するショートコードは、一時的なIPブロックをトリガーする可能性があります。 信頼性とボトルネック プライマリデータベースは最も重要な単一障害点です。緩和策:自動フェイルオーバー(例:Patroniのようなツールを使用)を備えた少なくとも1つのスタンバイへの同期レプリケーション。キャッシュレイヤーは、一時的なデータベースの劣化中でも読み取りを提供することで可用性を向上させます。IDジェネレーター自体も高可用性である必要があります。各APIノードに埋め込まれたSnowflakeスタイルのジェネレーター(ノードID +タイムスタンプ +シーケンスを使用)は、これを個別の依存関係として排除します。可能性のあるボトルネック:トラフィックピーク時のデータベース書き込みパス(接続プーリングと可能な場合の書き込みバッチングで緩和)、および一意のショートコードの突然の急増時のキャッシュエビクション(人気のあるリンクの事前ウォームとキャッシュサイズの調整で緩和)。 トレードオフと仮定 302(一時)リダイレクトを301(永続)の代わりに使用すると、ブラウザはリダイレクトをキャッシュしないため、すべての訪問がサービスにヒットします。これは意図的であり、正確なクリックカウントを可能にし、リンクの更新または削除を可能にします。トレードオフは、301よりもわずかに高いレイテンシと負荷です。シーケンシャルIDのBase-62エンコーディングは、おおよその作成順序を漏らします。それが懸念事項である場合、IDはハッシュされるか、一意性チェック(衝突時のリトライ)でランダムコードが生成される可能性があります。この設計は、匿名リンク作成が許可されていることを前提としています。認証を追加すると、不正利用制御が改善されますが、アクセシビリティが低下します。クリックカウントは、厳密なトランザクションインクリメントではなく、最終的な一貫性(Redisでバッファリングされ、非同期でフラッシュされる)を使用し、データベースへの書き込み負荷を大幅に低減する代わりに、わずかな不正確さを受け入れます。カスタムエイリアスはサポートされていますが、少数派のユースケースとして扱われ、コア生成パイプラインには影響しません。
判定
勝利票
3 / 3
平均スコア
総合点
総評
URL短縮サービスのデザインは、非常に構造化されており、包括的で、実践的です。プロンプトのすべての側面を良好な詳細レベルで扱っており、具体的な選択を行い、それらを効果的に正当化しています。強みとしては、堅牢なデータモデル、よく考えられた短縮コード生成戦略、読み取り負荷の高いトラフィックに対する包括的なスケーリング計画、そして301対302リダイレクトやクリック数の一貫性に関するトレードオフの強力な議論が挙げられます。潜在的なボトルネックを特定し、現実的な緩和戦略を提案しており、高トラフィックサービスのためのシステム設計原則をしっかりと理解していることを示しています。重大な弱点はなく、設計は高レベルでの実装議論の準備ができています。
採点詳細を表示 ▼
設計の質
重み 30%提案されたアーキテクチャは非常に一貫性があり、指定されたワークロードに適しています。ステートレスAPIティア、分散IDジェネレーター、読み取りレプリカを備えたリレーショナルデータベース、分散キャッシュ(Redis)、CDNなどの主要コンポーネントを明確に概説しています。これらのコンポーネント間の論理的な分離と相互作用がよく説明されており、機能的および非機能的要件を効率的に満たす強力なアーキテクチャ基盤を示しています。
完全性
重み 20%回答は非常に包括的で、プロンプトで要求されたすべての項目を詳細に網羅しています。コア要件および非機能要件から、APIエンドポイント、データモデル、短縮コード生成、読み書きフロー、ストレージ、キャッシング、スケーリング、リンク管理、不正利用防止、信頼性、そして明示的なトレードオフ/仮定まで、すべてが包括的かつ明瞭に説明されています。具体的なメトリクスと妥当な推定値の追加は、その完全性をさらに強化しています。
トレードオフの説明力
重み 20%回答は、重要な設計上のトレードオフについて優れた理由を提供しています。302対301リダイレクトの明示的な議論、シーケンシャルID生成の影響、プライマリデータベースの強い整合性の選択、クリック数の一貫性に関する結果整合性は、すべてよく正当化されています。これらの説明は、実際のシステムにおける設計上の選択の実際の結果を深く理解していることを示しています。
拡張性・信頼性
重み 20%設計は、スケーラビリティと信頼性に対して堅牢なアプローチを提示しています。ステートレスAPI、読み取りレプリカ、シャード化されたキャッシュ(Redis Cluster)、CDN統合を通じて、大量の読み取りトラフィックに効果的に対処しています。信頼性については、データベースのSPOF(単一障害点)緩和(レプリケーション、フェイルオーバー)、キャッシュレイヤーの耐障害性、IDジェネレーターの高可用性を考慮しています。潜在的なボトルネックを特定し、提案された緩和策は、負荷下でのパフォーマンスと稼働時間の維持に対する積極的なアプローチを示しています。
分かりやすさ
重み 10%回答は非常に明確で、整理されており、理解しやすいです。各セクションに明確な見出しがあり、プロンプトの構造に完全に一致しています。言語は正確で専門的であり、可能な限り専門用語を避けているため、複雑な技術設計がアクセスしやすくなっています。詳細の深さは高レベル設計として適切であり、実装の詳細に陥ることなく実践できるほど具体的です。
総合点
総評
キャッシュ/CDNとステートレスサービスによる読み取り中心のスケーリングを備えた、明確なAPI、データモデル、コード生成戦略、および実装可能な一貫した設計。有効期限/削除、基本的な不正利用制御に対処し、主要なボトルネックを特定しています。いくつかの領域はやや楽観的または仕様が不十分ですが(例:リダイレクトのCDNキャッシュ、404と410の一貫性/セマンティクス、詳細なキャッシュ無効化パターン、マルチリージョンに関する考慮事項、単一プライマリを超える書き込みスケーリング)、全体としてはワークロードによく適合し、妥当なトレードオフを含んでいます。
採点詳細を表示 ▼
設計の質
重み 30%ステートレスAPIティア、RDBMSの前面にあるRedisキャッシュ、オプションのリードレプリカ、非同期クリックカウント、バックグラウンドでの有効期限クリーンアップ、オプションのCDNを備えたクリーンなアーキテクチャを提示しています。コンポーネントと責任はよく分離されており、フローはもっともらしいです。いくつかの設計上のポイントはやや不安定ですが(CDN/ブラウザでのリダイレクトキャッシュの動作、および単一プライマリへの長期的な依存)、全体としては強力です。
完全性
重み 20%要求されたすべての項目を網羅しています:機能/非機能要件、エンドポイント、スキーマ、一意性アプローチ、読み取り/書き込みフロー、ストレージ+キャッシュ、読み取り中心トラフィックのスケーリング、有効期限/削除、不正利用/レート制限、信頼性/ボトルネック、トレードオフ/仮定。マイナーなギャップ:エイリアス正規化/予約語に関する議論が限定的、リンク更新のセマンティクス(許可されている場合)、および期限切れ/削除済み(404 vs 410)およびキャッシュ無効化のより明確な動作。
トレードオフの説明力
重み 20%301 vs 302、シーケンシャルID漏洩 vs ハッシュ/ランダム、クリックカウントの最終的な一貫性に関する良好な議論。RDBMSとキャッシュの選択肢の長所/短所を指摘しています。SQL vs NoSQLのこの規模での比較、レプリカラグの意味、CDNキャッシュとキャッシュTTL選択肢の運用上のトレードオフについて、より深く掘り下げることができますが、主要なトレードオフは認識され、正当化されています。
拡張性・信頼性
重み 20%読み取り中心のワークロードに対して合理的なスケーリング計画:キャッシュ、レプリカ、シャード化されたRedis、水平APIスケーリング、オプションのCDN、およびDB書き込みを削減するためのバッファリングされたカウンター。信頼性については、フェイルオーバーと中央IDサービス依存関係の削除に言及しています。欠けている/限定的:マルチリージョン戦略、DR/バックアップ、キャッシュ障害の処理(フォールバック動作)、およびデータが単一プライマリを快適に超えて成長した場合のより具体的な容量/パーティショニング戦略。
分かりやすさ
重み 10%見出し、具体的なエンドポイントの形状、明確なデータフィールド、段階的な読み取り/書き込みフローにより、よく構成されています。仮定と数値は追跡しやすいです。いくつかの記述はより明確または正確である可能性がありますが(特に302リダイレクトのキャッシュに関して)、全体的な可読性は高いです。
総合点
総評
このシステム設計の回答は非常に強力で、構造化されており、要求されたトピックを適切な深さで網羅しています。ワークロード(平均8書き込み/秒、80読み取り/秒)を正しく推定し、ステートレスAPIノード、リレーショナルデータベース、Redisキャッシュ、分散IDジェネレータを備えた一貫性のあるアーキテクチャを提案しています。回答は、機能要件、非機能要件、APIエンドポイント、データモデル、短いコード生成、読み書きフロー、ストレージとキャッシュ、スケーリング、有効期限/削除、不正利用防止、信頼性、トレードオフに関するプロンプトの12の箇条書きすべてに対応しています。トレードオフの理由は思慮深く具体的です。例えば、302対301の議論、シーケンシャルコード対ランダムコード、クリックカウントの最終的な一貫性、302レスポンスに対するCDNキャッシュのニュアンスです。スケーリングアプローチは現実的で、ワークロードに適しています。わずかな弱点として、NoSQLを代替ストレージオプションとして(リレーショナルに言及するのみ)、302レスポンスに対するCDNの議論をもう少し拡大できた可能性、単一プライマリを超えた将来の成長のためのデータベースパーティショニング/シャーディングの議論が欠けていることが挙げられます。不正利用防止セクションは堅実ですが、URLスキャンサービスやセーフブラウジングAPIに言及できたでしょう。全体として、これは実装可能で、優れたシステム設計思考を示す高品質な回答です。
採点詳細を表示 ▼
設計の質
重み 30%アーキテクチャは一貫性があり、ワークロードに適しています。ステートレスAPIティア、読み取りレプリカを持つリレーショナルDB、Redisキャッシュ、SnowflakeスタイルのID生成、オプションのCDNは、合理的なスタックを形成します。読み書きフローは明確に分離されており、論理的です。IDジェネレータをAPIノードに埋め込むという選択は、独立した依存関係を排除する良い設計上の決定です。わずかなギャップ:将来の成長のためのデータベースシャーディングに関する議論が単一プライマリを超えた場合に欠けており、アーキテクチャにおけるNoSQLの代替案の明示的な検討がありません。
完全性
重み 20%回答は、プロンプトで要求された12の箇条書きすべてを網羅しています。機能要件と非機能要件は明確に述べられ、APIエンドポイントはHTTPメソッドとレスポンスコードで明確に定義され、データモデルは合理的なフィールドとインデックスを含み、短いコード生成は容量計算とともに説明され、読み書きフローは詳細に説明され、ストレージとキャッシュは定量化され、スケーリングが対処され、有効期限と削除は読み取り時とバックグラウンドジョブの両方で処理され、不正利用防止にはレート制限とブロックリストが含まれ、信頼性に関する考慮事項は主なSPOFと緩和策を特定し、トレードオフは明示的に議論されています。カスタムエイリアスが処理されています。欠けている点はほとんどありません。
トレードオフの説明力
重み 20%トレードオフの理由は顕著な強みです。302対301の議論は、明確な根拠とともにうまく説明されています。シーケンシャルコード生成対ランダムコード生成のトレードオフは、実用的な緩和策(ハッシュ化)とともに言及されています。クリックカウントの最終的な一貫性は、明確なコスト便益分析によって正当化されています。302レスポンスに対するCDNキャッシュのニュアンスは、深い理解を示しています。SQL対NoSQLのトレードオフの明示的な議論と、さまざまなキャッシュTTL戦略のトレードオフに関する詳細があれば、より強力になった可能性があります。
拡張性・信頼性
重み 20%スケーリングアプローチは現実的です:水平APIスケーリング、読み取りレプリカ、Redis Clusterシャーディング、エッジでのCDN。ワークロード計算は正確で、キャッシュサイジングの推定は合理的です。信頼性は、同期レプリケーション、自動フェイルオーバー、および埋め込みIDジェネレータ設計で対処されています。ボトルネック(DB書き込みパス、キャッシュエビクション)が特定されています。ただし、データセットが単一プライマリの容量を大幅に超えて成長した場合のデータベースシャーディングやパーティショニング戦略、地理的分布やマルチリージョン展開については言及されていません。
分かりやすさ
重み 10%回答は非常に整理されており、プロンプトの要件に直接対応する明確なセクションヘッダーがあります。各セクションは簡潔でありながら実質的です。技術用語は正しく一貫して使用されています。文章はプロフェッショナルで理解しやすいです。要件からアーキテクチャ、トレードオフへの流れは論理的です。不要な冗長性や脱線したコンテンツはありません。