系统设计入门:2026 年如何设计 URL Shortener
Source: Dev.to
系统设计面试让大多数开发者感到恐惧。问题开放式,范围庞大,而且没有唯一的“正确”答案。
但秘密是:每个系统‑design 问题都遵循相同的框架。一旦你用一个简单的例子学会了它,就可以将其应用到任何场景。
我们将使用 URL 短链接服务——最经典的系统‑design 问题——作为学习载体。
什么是系统设计?
系统设计是定义系统的架构、组件、模块、接口和数据流以满足给定需求的过程。
在面试中,你经常会被要求设计以下系统:
- URL 短链接(bit.ly)
- Twitter/X 时间线
- YouTube
- Uber 的乘车调度
- Netflix 视频流
系统设计框架(6 步)
1. 明确需求
2. 估算规模
3. 定义 API
4. 设计数据模型
5. 绘制高层架构
6. 深入组件细节让我们把每一步应用到 URL 缩短服务上。
步骤 1:明确需求
功能需求(系统要做什么)
- 给定一个长 URL,生成一个短 URL(例如
bit.ly/abc123)。 - 给定一个短 URL,重定向到原始的长 URL。
- 短 URL 应在可配置的时间后失效(可选)。
- 用户可以创建自定义短 URL(可选)。
非功能需求(系统要做到什么程度)
- 高可用性 – 可用时间达 99.9 %。
- 低延迟 – 重定向在
要点: 该系统以读为主,需要大量缓存,存储需求适中。
步骤 3:定义 API
POST /api/v1/urls
Request:
{
"longUrl": "https://example.com/very/long/path",
"expiresAt": "2027-01-01"
}
Response:
{
"shortUrl": "https://bit.ly/abc123",
"expiresAt": "2027-01-01"
}GET /{shortCode}
Response: 301 Redirect to longUrlDELETE /api/v1/urls/{shortCode}
Response: 200 OK301 与 302 重定向
- 301(永久) – 浏览器会缓存重定向 → 对我们服务器的请求更少 → 成本更低。
- 302(临时) – 浏览器每次都会访问我们的服务器 → 可获得更精确的分析数据。
根据产品需求进行选择。
步骤 4:设计数据模型
表结构(SQL 示例)
CREATE TABLE urls (
short_code VARCHAR(7) PRIMARY KEY,
long_url VARCHAR(2048) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP,
user_id BIGINT, -- 匿名用户时可为空
click_count BIGINT DEFAULT 0
);
CREATE INDEX idx_short_code ON urls(short_code);short_code 为主键。下面列出三种常见的生成策略。
短码生成策略
选项 1 – 哈希 + 截断
import hashlib
def generate_short_code(long_url: str) -> str:
hash_value = hashlib.md5(long_url.encode()).hexdigest()
return hash_value[:7] # MD5 的前 7 位字符问题: 哈希冲突(不同的 URL 可能得到相同的短码)。
选项 2 – 基于计数器的 Base62 编码
BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encode_base62(num: int) -> str:
if num == 0:
return BASE62[0] * 7
result = []
while num > 0:
result.append(BASE62[num % 62])
num //= 62
return ''.join(reversed(result)).zfill(7)工作原理: 在数据库中原子递增计数器,然后进行编码。保证唯一性。✅
选项 3 – 预生成密钥(密钥生成服务)
- 预先填充
keys_available表,包含数百万唯一的 7 字符串。 - 当需要短 URL 时,取出一个密钥并移动到
keys_used。 - 完全消除冲突风险。
步骤 5:高层架构
[Client]
│
▼
[Load Balancer]
│
├─── [Write Service] ──── [Primary DB]
│ │
└─── [Read Service] ──── [Redis Cache] ──── [Read‑Replica DB]写入路径
- 客户端 POST 一个长 URL。
- 写入服务生成短码(Base62 计数器或 KGS)。
- 将映射保存到主库。
- 将短 URL 返回给客户端。
读取路径
- 客户端 GET
/{shortCode}。 - 读取服务先查询
Redis(≈ 99 % 命中率)。 - 未命中时查询只读副本库。
- 发起 301/302 重定向。
步骤 6:深入探讨 – 缓存策略
每秒约 116 K 次读取,单靠数据库无法跟上;Redis 是必不可少的。
import redis
cache = redis.Redis(host='localhost', port=6379)
CACHE_TTL = 3600 # 1 小时
def get_long_url(short_code: str) -> str | None:
# 1️⃣ 先尝试缓存
cached = cache.get(f"url:{short_code}")
if cached:
return cached.decode()
# 2️⃣ Cache miss → query DB
long_url = db.query(
"SELECT long_url FROM urls WHERE short_code = %s", short_code
)
# 3️⃣ Populate cache for future hits
if long_url:
cache.setex(f"url:{short_code}", CACHE_TTL, long_url)
return long_urlCache eviction policy: LRU(最近最少使用)。根据 80/20 法则,约 20 % 的 URL 承担约 80 % 的流量——缓存这 20 % 的热点。
常见后续问题
Q: How do you handle expired URLs?
- Lazy deletion: 在读取时检查
expires_at;如果已过期,返回 410 Gone。 - Background job: 定期扫描表并删除过期行(或将其移动到归档)。
Q: How would you support custom aliases?
- 验证请求的别名是否唯一且不含不当语言。
- 直接将其存为
short_code;若冲突,返回错误。
Q: How can you make the system globally distributed?
- 在多个地区部署读副本和 Redis 缓存。
- 使用 geo‑DNS 或 anycast 负载均衡器将用户路由到最近的地区。
- 采用一致性哈希方案生成键,以避免跨数据中心的冲突。
Q: How would you collect analytics (click counts, referrers, etc.)?
- 通过消息队列(例如 Kafka)异步递增
click_count列。 - 将详细事件存入时序数据库或数据仓库,以便后续分析。
Q: What if the short‑code space (7 chars, Base62) runs out?
- 切换到 8 位代码(62⁸ ≈ 2.18 × 10¹⁴ 种可能)。
- 或在安全的宽限期后回收未使用/已过期的代码。
TL;DR
- Clarify 功能性和非功能性需求。
- Estimate 流量、存储和延迟需求。
- Define 干净、版本化的 API。
- Model 数据(URL ↔ short code)并决定生成策略。
- Sketch 高层架构,包含独立的写/读服务、主数据库、读副本和 Redis 缓存。
- Dive 关键组件(缓存、过期处理、分析、全局分布)。
遵循此框架,你就能应对任何系统设计面试——从经典的 URL 缩短服务开始。 🚀
ed URLs 每夜
问:如何防止滥用?
- 对每个 IP 进行速率限制(Redis 滑动窗口计数器)
- 阻止恶意 URL(Safe Browsing API)
- 对匿名用户使用 CAPTCHA
问:如何扩展到每日 10 B 请求?
- 增加读取副本
- 地理分布(用于重定向的 CDN)
- 对分布式缓存使用一致性哈希
问:自定义短码?
- 保存前检查唯一性
- 为保留/自定义码使用单独的表
面试官实际评估的内容
- 沟通 – 你能清晰地阐述你的思路吗?
- 权衡 – 你是否理解每个决定背后的原因?
- 规模意识 – 你在动手之前会进行估算吗?
- 深度 – 当被要求时,你能对至少一个组件进行深入探讨吗?
你不需要完美的答案。你需要引导对话,做出合理的选择,并解释你的推理。
实践题目(难度递增)
- URL Shortener(本文)– 从这里开始
- Pastebin – 文本共享
- Rate Limiter – 经典 API 设计
- Twitter Timeline – 粉丝流问题
- Design YouTube – 视频存储 + 流媒体
- Design Uber – 实时匹配
在学习系统设计的同时管理自由职业项目和客户?
Freelancer OS 将一切组织起来 — CRM、项目、收入,全部在 Notion 中。一次性 €19。