Skip to content

让你设计一个短链系统,怎么设计? ​

  • 标签:后端、系统设计、场景题

🏛 业务架构师 ​

短链系统的业务动机先说清:长 URL 太长太丑——短信营销按字计费(一条 70 字,长 URL 吃掉大半)、印刷物料空间有限、且需要点击追踪(哪个渠道带来转化)。技术是小事,它本质是"映射服务 + 投放追踪资产"。

核心设计:

1. 发号与编码

  • 短码用 62 进制(a-z A-Z 0-9),6 位 = 568 亿组合,够任何业务;
  • 发号器用分布式 ID(号段/雪花),短码有序可预测有枚举风险——对安全敏感场景(内部链接)加随机置换或校验位;
  • 长链去重:长 URL hash 做 key 查重,同一 URL 复用短码(省空间,也保证统计口径一致)。

2. 跳转服务(读路径是性能生命线)

  • 301 永久跳转 vs 302 临时跳转:301 浏览器缓存后不再访问短链服务——你丢失了后续点击统计!要追踪就 302(每次点击都过服务),这是业务需求(统计)驱动技术选型的教科书例子;
  • 缓存:短码→长URL 全量放 Redis(数据量小、读极高),DB 只兜底——QPS 十万级轻松;
  • 热点短码(爆款活动链接)本地缓存再挡一层。

3. 追踪与数据

点击事件异步落日志(UA、IP、渠道参数)→ 数仓分析转化——短链的商业价值大半在这:投放 ROI、渠道归因。

4. 治理

短码过期回收(活动结束 404 或下线页)、恶意链接检测(接安全扫描,短链服务被滥做成钓鱼跳板是合规大坑)、防刷限流。

演进路线:单库 + 缓存起步,量级上来分库(短码 hash 或号段路由),十亿级前不需要分片——按业务规模投入,别第一天就上分布式。

🏗 系统架构师 ​

短链系统(如 t.cn/Ab3xK9)我按"发号 → 存储 → 跳转 → 扩展"四块设计:

1. 编码生成:

  • 发号器 + 62 进制:全局 ID(雪花或号段模式)→ 转 62 进制(a-z A-Z 0-9),6 位可表达 568 亿,够用且趋势递增、无冲突——我的首选;
  • Hash(MD5 取前 6 位):要处理冲突(查库比对、加长重试),且不递增,不选;
  • 预生成号池:提前批量生成进队列取用,削峰。

2. 存储与查询:MySQL 存 短码 ↔ 长链 + 过期时间 + 业务方,短码做主键(点查 O(1));Redis 全量缓存热点映射(短链读是典型读多写少,命中率 99%+),布隆过滤器防穿透。容量估算:1 亿条短链 × 200B ≈ 20GB,单表分表即可。

3. 跳转链路(高并发核心):短链服务无状态多副本 + 负载均衡 → 本地缓存(Caffeine)→ Redis → DB 兜底;302(可统计跳转)vs 301(浏览器缓存,省流量但少统计)——运营场景选 302;异步打点(点击 UV/来源)进 MQ 聚合分析,不阻塞跳转主链路(目标 P99 < 10ms)。

4. 治理:短链过期与淘汰(LRU 清理)、防滥用(黑名单长链、频控)、自定义后缀冲突检测、监控命中率与穿透率。

设计要点一句话:短链本质是"发号器 + KV 读缓存"架构,难点不在存储在读写比极高的跳转链路性能。

💻 全栈开发专家 ​

核心链路:发号 → 编码 → 存储 → 跳转。

1. 发号器:全局自增 ID(号段模式或雪花)。不要用 MD5 短哈希——不可读且冲突要处理;自增号 + 进制转换最简单。

2. 62 进制编码(0-9a-zA-Z),短码长度:62^7 ≈ 3.5 万亿,够用且比 16 进制短:

java
private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String encode(long id) {
    StringBuilder sb = new StringBuilder();
    while (id > 0) { sb.append(CHARS.charAt((int) (id % 62))); id /= 62; }
    return sb.toString();
}

3. 存储设计:

sql
CREATE TABLE short_url (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  code VARCHAR(16) NOT NULL UNIQUE,   -- 短码(或直接用 id 编码)
  long_url VARCHAR(2048) NOT NULL,
  expire_at DATETIME,
  KEY idx_code (code)
);

长 URL 查重可加 long_url 的索引/哈希列。量级上来分表:按 code 首字母或 id 取模。

4. 跳转语义(必答题):301 永久跳转浏览器会缓存,后续不再回源——省服务器但统计不到点击;302 临时跳转每次回源,可埋点统计。业务要统计就 302,同时扛住读 QPS。

5. 高并发读优化:短码 → 长 URL 是典型读多写少,Redis 缓存(code 为 key,TTL 同过期时间)+ 本地缓存二级;不存在恶意扫描的 code 用布隆过滤器挡掉,防缓存穿透。

坑:自定义短码要防保留字(api、admin);过期与失效清理用惰性判断(跳转时校验)+ 异步归档。