[システムデザインインタビュー] URL短縮サービスをゼロから実装する
コードはGitHubで確認できます。
概要
URLの短縮は、もともとメールやSMSでURLが分断されるのを防ぐために始まりました。しかし、現在ではTwitterやInstagramなどのソーシャルメディアプラットフォームで特定のリンクを共有するためにより積極的に使用されています。URLが冗長に見えないことで可読性が向上し、リダイレクト前にユーザーの統計情報を収集するなどの追加機能も提供できます。
この記事では、URL短縮サービスをゼロから実装し、その仕組みを探ります。
URL短縮サービスとは?
まず、結果を見てみましょう。
この記事で実装するURL短縮サービスは、以下のコマンドで直接実行できます。
docker run -d -p 8080:8080 songkg7/url-shortener
使用方法は簡単です。短縮したい長いURLをlongUrl
の値として入力します。
curl -X POST --location "http://localhost:8080/api/v1/shorten" \
-H "Content-Type: application/json" \
-d "{
\"longUrl\": \"https://www.google.com/search?q=url+shortener&sourceid=chrome&ie=UTF-8\"
}"
# ランダムな値(例:tN47tML)が返されます。
次に、http://localhost:8080/tN47tML
にアクセスすると、
元のURLに正しくリダイレクトされることが確認できます。
短縮前
短縮後
では、どのようにしてURLを短縮するのか見てみましょう。
大まかな設計
URLの短縮
- longUrlを保存する前にIDを生成します。
- IDをbase62にエンコードしてshortUrlを作成します。
- ID、shortUrl、およびlongUrlをデータベースに保存します。
メモリは有限で比較的高価です。RDBはインデックスを通じて迅速にクエリを実行でき、メモリに比べて比較的安価なので、URLの管理にはRDBを使用します。
URLを管理するためには、まずID生成戦略を確保する必要があります。ID生成にはさまざまな方法がありますが、ここでは長くなるため省略します。今回は単純に現在のタイムスタンプを使用してIDを生成します。
Base62変換
ULIDを使用すると、タイムスタンプを含む一意のIDを生成できます。
val id: Long = Ulid.fast().time // 例:3145144998701、プライマリキーとして使用
この数値をbase62に変換すると、次のような文字列になります。
tN47tML
この文字列はshortUrlとしてデータベースに保存されます。
id | short | long |
---|---|---|
3145144998701 | tN47tML | https://www.google.com/search?q=url+shortener&sourceid=chrome&ie=UTF-8 |
取得プロセスは次のように進行します:
localhost:8080/tN47tML
にGETリクエストを送信します。tN47tML
をbase62からデコードします。- プライマリキー3145144998701を取得し、データベースをクエリします。
- リクエストをlongUrlにリダイレクトします。
これで大まかな流れを見たので、実装して詳細を掘り下げていきましょう。
実装
前回の記事「Consistent Hashing」と同様に、自分で実装します。幸いなことに、URL短縮サービスの実装はそれほど難しくありません。
モデル
まず、ユーザーからのリクエストを受け取るモデルを実装します。短縮するURLのみを受け取るように構造を簡略化しました。
data class ShortenRequest(
val longUrl: String
)