高效短链系统的设计方案记录
引言
当你刷抖音看到“https://v.douyin.com/xyz123”时,当你点开微博的“t.cn/abcd56”时——这些仅有6-8个字符的链接,就是现代互联网的“空间折叠术”:**短链**。
短链是什么?
定义:通过算法将原始长链接(如商品页URL)压缩成极短字符串,实现“轻量化跳转”。
1 | 原链接 → https://www.某电商.com/product/123456789?source=weibo 短链 → t.cn/AbcD12 |
核心价值:
- 用户体验:避免长链接在社交平台“刷屏污染”
- 流量追踪:统计点击量、用户来源等关键数据
- 安全控制:隐藏真实URL参数,防止恶意篡改
为什么需要千亿级短链系统?
以抖音为例:
- 日均生成量:10亿+条(电商链接、视频分享、广告追踪)
- 峰值QPS:每秒超50万次生成请求(顶流明星发帖时)
- 存储规模:千亿级数据需保存3-6个月
一、*场景痛点:为什么你的短链系统会崩?*
1. 经典错误方案复现
1 | // 错误案例:直接Hash生成短码(面试中这样答直接挂!) public String createShortUrl(String longUrl) { String md5 = DigestUtils.md5Hex(longUrl); return md5.substring(0, 6); // 6位短码,冲突率高达22% } |
崩溃三宗罪:
- 哈希冲突:6位短码仅能存储 568亿种组合,千亿级数据必然冲突
- 热Key问题:热门长链生成请求集中攻击单Redis节点
- 存储瓶颈:单表数据过亿后,MySQL查询延迟飙升
二、*工业级方案*
1. 分布式ID生成:短码不重复的核心
方案对比:
方案 | 生成速度 | 冲突概率 | 适用场景 |
---|---|---|---|
Snowflake | 10万/秒 | 0 | 分布式环境 |
Redis原子INCR | 5万/秒 | 0 | 小规模系统 |
UUID | 1万/秒 | 0 | 无序列要求场景 |
优化版Snowflake代码:
1 | public class ShortCodeGenerator { // 时间戳(41位) + 数据中心ID(5位) + 机器ID(5位) + 序列号(13位) private static final int TOTAL_BITS = 64; private static final int TIMESTAMP_BITS = 41; private static final int SEQUENCE_BITS = 13; |
2. 分库分表:千亿级数据存储方案
分片策略:
- 一级分片:按短码首字符分库(Base62共62种字符 → 62个库)
- 二级分片:按短码CRC32哈希值分表(单库分1024表)
拓展知识:为什么在短链系统设计中选用 Base62 而非 Base64?
维度 | Base62 | Base64 |
---|---|---|
字符集 | 0-9 + A-Z + a-z (62个) |
0-9 + A-Z + a-z + + / (64个) |
URL安全 | ✅ 无特殊字符,直接使用 | ❌ 需转义 + 和 / |
分片管理 | ✅ 首字符直接映射62分片 | ❌ 需处理特殊字符 |
适用场景 | 短链、API Key、邀请码等 | 二进制数据编码(如图片传输) |
3. 缓存设计:抗住百万QPS的秘诀
三级缓存体系:
- 本地缓存:Caffeine存储热点短链(TTL=1分钟,命中率30%)
- Redis集群:CRC16分片 + 数据压缩(节省40%内存)
- 布隆过滤器:拦截99.9%非法短码请求(误判率0.1%)
Redis Lua脚本(原子写入):
1 | -- KEYS[1]=短码, ARGV[1]=长链接 if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('EXPIRE', KEYS[1], 604800) -- 7天过期 return 1 else return 0 end |
三、*高可用设计:如何做到全年无宕机?*
1. 多机房双活架构
- 流量调度:基于RTT延迟自动选择最优机房
- 数据同步:使用Binlog + Kafka实现跨机房同步
2. 熔断降级策略
规则:
- Redis CPU >70% → 关闭非核心功能(如访问统计)
- MySQL响应时间 >500ms → 返回静态缓存页
Sentinel配置示例:
1 | @SentinelResource(value = "shortUrlService", blockHandler = "handleBlock", fallback = "handleFallback") public String getLongUrl(String shortCode) { // 核心业务逻辑 } |
四、*实战避坑指南*
短码安全问题:
- 禁止连续字符:通过正则过滤
aaaaaa
类短码 - 时效控制:设置7天过期时间,清理僵尸数据
- 禁止连续字符:通过正则过滤
数据迁移方案:
- 双写机制:新旧系统并行运行3天
- 校验工具:对比新旧库差异率,确保<0.001%
** **
技术总结
- 分治思想:千亿级问题拆解为ID生成、分片存储、缓存优化
- 冗余设计:多机房、多副本保障高可用
- 成本控制:冷热分离 + 数据压缩降低存储费用
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Calico's Space!
评论