极高 进阶
短链系统设计#
一句话答案#
长 URL→全局 ID/哈希→Base62 编码→短码,存储映射关系,访问时 302 重定向到原 URL,Redis 缓存热门短链。
核心要点
流程:
- 生成:长URL → 全局ID/哈希 → Base62 编码 → 存储映射
- 访问:短码 → 查 Redis/DB → 302 重定向
核心问题:
- 唯一性:自增ID+Base62(推荐)或 MurmurHash+冲突处理
- 性能:Redis 缓存热门短链
- 过期:TTL 定期清理
面试回答(2分钟版)
短链系统的核心是把长URL映射成6位短码然后做重定向。生成短码主流两种方案:一是用发号器生成全局自增数字(数据库号段模式、Redis INCR 等),再做Base62编码,6位Base62能表示约568亿种组合完全够用——注意雪花算法的 ID 是 64 位大数(约 19 位十进制),Base62 后约 11 位,做不到 6 位短码;二是对长URL做MurmurHash取前几位,但需要处理哈希冲突,可以用布隆过滤器做判重。存储上用MySQL存长短链映射关系,Redis缓存热门短链提升查询性能。用户访问时,短码先查Redis再查DB,找到原始URL后做302临时重定向,用302而不是301是因为301会被浏览器永久缓存导致无法统计点击量。过期短链通过TTL加定时任务清理。整体架构就是接入层Nginx做负载均衡,服务层处理编码和查询逻辑,数据层MySQL加Redis,日访问量大的话可以按短码前缀做分库分表。
追问与易错
追问方向:
- “用 301 还是 302 重定向?为什么?”→ 用 302 临时重定向,浏览器每次都请求短链服务,方便统计点击次数和做访问分析;301 永久重定向会被浏览器缓存,后续访问不再经过服务端无法统计
- “短码冲突怎么处理?”→ 自增 ID 方案天然无冲突;哈希方案冲突时用布隆过滤器快速判重(布隆说「不存在」一定不存在,说「存在」可能误判,直接当冲突处理即可),冲突则在原 URL 后拼接随机串重新哈希,直到不冲突为止;最终以 DB 上短码的唯一索引兜底
- “过期短链怎么清理?”→ Redis 缓存设 TTL 自动过期;DB 中通过定时任务扫描过期时间字段批量删除或标记失效;短码一般不回收复用,否则旧链接(已被转发、印在海报上)会跳到新内容
易错点:
- ❌ “用 MD5 截取就不会冲突”——哈希碰撞难以避免,需要碰撞处理机制
- ❌ “短链越短越好”——6 位 Base62 = 62^6 ≈ 568 亿种组合,已经足够
- ❌ “雪花 ID 转 Base62 就是 6 位”——64 位雪花 ID 转出来约 11 位,要 6 位短码得用从小数开始的发号器
- ❌ 自增 ID 直接 Base62 暴露出去——短码连续可被遍历爬取,可对 ID 做一次可逆混淆(如乘法逆元/Feistel 置换)再编码