首次归档:2026-09-13 R5 | 难度:高阶
场景:
设计一个短链接系统,支撑 日均 5 亿次短链生成 + 20 亿次跳转,跳转 P99 < 50ms,可用性 99.99%。
问题:
(未作答,进入讲解模式)
优点:暂无
不足:ID 生成选型、多级缓存、高可用兜底是系统设计必考。
补充:完整讲解见下。
得分:N/A
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 自增 + base62 | 顺序、无冲突、ID 短 | DB 瓶颈 | 低并发 |
| Snowflake | 无中心依赖 | 时钟回拨 | 高并发 |
| 哈希 | 无状态 | 冲突率高 | 低冲突要求 |
| 发号器(分布式) | 无冲突、可控 | 需额外服务 | 超高并发 |
推荐:发号器 + base62 编码
// Redis 原子递增
String key = "id_gen:" + LocalDate.now();
Long id = redisTemplate.opsForValue().increment(key);
return Base62Encoder.encode(id);
延迟预算(总 50ms):
| 环节 | 延迟预算 |
|---|---|
| DNS 解析 | 1-5ms |
| CDN 边缘 | 5-10ms |
| 短链服务查询 | 10-20ms |
| 302 跳转 | 5-10ms |
| 缓冲 | 10ms |
多级缓存:
L1: 本地缓存(Caffeine)→ L2: Redis → L3: DB
| 缓存层 | 命中率 | 延迟 |
|---|---|---|
| L1 | 30% | < 1ms |
| L2 | 60% | 5-10ms |
| L3 | 10% | 50-100ms |
| 加权平均 | - | ~10ms |
DB 设计:short_link_0 ~ short_link_15 按 hash(short_code) % 16 分表。
冲突检测:
if (exists(customCode)) throw new DuplicateException();
// 唯一索引兜底(并发场景)
CREATE TABLE short_link (short_code VARCHAR(16) PRIMARY KEY, ...);
缓存雪崩防护:随机过期时间 + 热点 key 永不过期
热点 key 防护:滑动窗口计数器检测热点 → 强制加载本地缓存
单机故障:多实例 + LB + 客户端重试
降级:Redis 挂 → 直查 DB;DB 挂 → 熔断返回错误