1. 厘清需求(Requirements)

功能性需求:

  • 给一个长 URL,返回一个唯一的短 URL。
  • 访问短 URL 时,重定向到原始长 URL。
  • (可选)自定义短码、链接过期时间、访问统计。

非功能性需求:

  • 高可用(服务挂了用户就打不开链接)。
  • 重定向低延迟
  • 短码不可预测(出于安全)。
  • 系统读多写少。

2. 容量估算(Capacity Estimation) —— 这一步很多人会漏,但评分里通常占分

假设每月新增 1 亿条短链,读写比约 100:1。

  • 写:100M / month ≈ 40 次/秒。
  • 读:约 4000 次/秒。
  • 存储:每条约 500 字节,5 年 ≈ 60 亿条 ≈ 3 TB。
  • 短码长度:用 62 进制(a-z, A-Z, 0-9),7 位 = 62⁷ ≈ 3.5 万亿,足够用很多年。

3. API 设计


POST /shorten body: { longUrl, customAlias?, expireAt? } -> { shortUrl } GET /{shortCode} -> HTTP 301/302 重定向到 longUrl

重定向用 302(临时) 还是 301(永久):301 浏览器会缓存、减轻服务器压力,但你就拿不到点击统计;302 每次都回服务器,便于统计。面试里能说出这个权衡是加分点。

4. 数据模型

一张核心表即可:


url_mapping( short_code PK, long_url, created_at, expire_at, user_id )

因为是 key-value 式的查询(用 short_code 查 long_url),用 NoSQL(如 DynamoDB/Cassandra)或带缓存的关系库都行。

5. 核心:短码怎么生成? —— 这是这道题真正的考点


  • 预生成 + 发号服务(推荐):用一个独立的 ID 生成服务(如 Snowflake,或 Zookeeper/Redis 维护号段),各应用服务器批量领取一段 ID,再 Base62 编码。既避免单点瓶颈,又无冲突。

6. 整体架构 & 扩展性

读路径(重定向)是性能关键:

  • 前面放 缓存(Redis),缓存热门短码 → 长 URL 的映射,大部分读请求不落库。
  • 数据库做分片(按 short_code 哈希),配只读副本扛读流量。
  • 前置 CDN / 负载均衡,服务无状态、可水平扩展。
  • 发号服务用号段预分配,避免成为写瓶颈。

7. 收尾:可补充的点

限流防滥用、过期链接的清理(定时任务或惰性删除)、点击分析走异步消息队列(Kafka)避免拖慢重定向、监控告警。



API Design

POST /shorten body: { longUrl, customAlias?, expireAt? } -> { shortUrl } GET /{shortCode} -> HTTP 301/302 重定向到 longUrl

重定向用 302(临时) 还是 301(永久):301 浏览器会缓存、减轻服务器压力,但你就拿不到点击统计;302 每次都回服务器,便于统计。面试里能说出这个权衡是加分点。



读路径(重定向)是性能关键:

  • 前面放 缓存(Redis),缓存热门短码 → 长 URL 的映射,大部分读请求不落库。
  • 数据库做分片(按 short_code 哈希),配只读副本扛读流量。
  • 前置 CDN / 负载均衡,服务无状态、可水平扩展。
  • 发号服务用号段预分配,避免成为写瓶颈。



4. 数据模型

一张核心表即可:



url_mapping( short_code PK, long_url, created_at, expire_at, user_id )



Detailed Component Design

Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.