高并发短链接系统设计
面试题型 :后端系统设计面试题
难度等级 :⭐⭐⭐⭐
核心考点:分布式 ID 生成、缓存设计、高并发读优化、重定向原理
🎯 一句话定位
短链接系统解决什么问题?
把又长又丑的 URL(https://www.example.com/very/long/path?param1=value1¶m2=value2...)
变成又短又美的链接(http://t.cn/8M0kX)
生活化比喻 :
就像给长地址起个"昵称"------你的身份证号是 18 位数字,但朋友叫你"小明"就行了。短链接就是长 URL 的"昵称"。
核心特点:读多写少(100:1),就像微博,发微博的人少,看微博的人多。
💎 核心观点(5 分钟速览版)
如果只有 5 分钟,看这里就够了!
核心观点(5 个关键点)
1. 短码生成:分布式发号器 + Base62 编码
❌ 不用 MD5/UUID(有碰撞/太长)
✅ 用分布式 ID(雪花算法)+ Base62 编码
- 雪花算法:时间戳 + 机器 ID + 序列号 → 全局唯一
- Base62:0-9 + a-z + A-Z = 62 个字符,6 位可表示 568 亿
- 优势:天然唯一、无碰撞、高性能
2. 存储架构:MySQL 分库分表 + Redis 缓存
- MySQL:持久化存储,按短码 Hash 分 16 库 256 表
- Redis:热点数据缓存,命中率 80-90%
- 布隆过滤器:拦截 99% 不存在的短码,防穿透
3. 跳转优化:302 临时重定向
✅ 302(推荐):每次经过服务端,方便统计点击、可修改目标
❌ 301:浏览器缓存,无法统计,不可修改
混合方案:热点短链用 301 + CDN,普通短链用 302
4. 高并发优化:三级缓存架构
L1 本地缓存(Caffeine/GoCache):TTL 5 分钟,抗 10 万+ QPS
L2 Redis 缓存:TTL 24 小时,命中率 80-90%
L3 MySQL:永久存储,命中率 < 5%
5. 容量规划:6 位 Base62 可用 8 年
日活 1000 万 × 5 个/天 = 5000 万/天
6 位 Base62 容量 568 亿 → 可支撑 3000+ 天(约 8 年)
存储:50 字节/条 × 5000 万 = 2.5 GB/天
🚀 一句话精华(如果只能记住一句)
短链接系统 = 分布式发号器(保证唯一) + Base62 编码(缩短长度) + 三级缓存(扛高并发) + 302 重定向(方便统计)
一、为什么不用 MD5/UUID 做短码生成?
❌ MD5 方案的问题
思路:长 URL → MD5 哈希 → 截取 6-8 位 → 短码
三大致命缺陷:
1. 哈希碰撞(最致命)
生活化比喻:
就像给全班同学取昵称,只取名字最后一个字。
张三 → "三",李四 → "四",王五 → "五"...
但如果班上有个"张小三"和"王小三",都叫"三",就冲突了!
技术问题:
URL_A 和 URL_B 截取后都是 abc123,怎么办?
解决方案:碰撞后重试 + 数据库判重
代价:高并发下性能急剧下降(多次 DB 查询)
2. 不可控
就像拆盲盒,你不知道会拆出什么。
MD5 输出 32 位,截取后碰撞概率难以计算。
无法保证短码的唯一性和连续性。
3. 无业务含义
纯随机,无法做趋势分析。就像给商品编号用随机数,看不出销售趋势。
❌ UUID 方案的问题
- 长度过长(36 字符),不适合短链接场景(短链接要"短"啊!)
- 无序,数据库索引性能差(B+ 树频繁分裂,就像图书馆的书乱摆,找起来很慢)
- 同样存在碰撞概率(虽然极低)
二、生产级方案:分布式发号器 + Base62 编码
✅ 核心思路(30 秒版)
生活化比喻:
想象一个自动编号机(分布式发号器),每来一个长 URL,就给它一个唯一编号(123456789)。
然后把这个编号翻译成短码(Base62 编码:123456789 → "8M0kX")。
最后把映射关系存起来(短码 ↔ 长 URL)。
技术流程:
唯一数字ID(雪花算法) → Base62编码 → 6位短码(8M0kX) → 存储映射关系
#mermaid-svg-XCjpVQJDV7HTnwqh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XCjpVQJDV7HTnwqh .error-icon{fill:#552222;}#mermaid-svg-XCjpVQJDV7HTnwqh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XCjpVQJDV7HTnwqh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XCjpVQJDV7HTnwqh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XCjpVQJDV7HTnwqh .marker.cross{stroke:#333333;}#mermaid-svg-XCjpVQJDV7HTnwqh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XCjpVQJDV7HTnwqh p{margin:0;}#mermaid-svg-XCjpVQJDV7HTnwqh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster-label text{fill:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster-label span{color:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster-label span p{background-color:transparent;}#mermaid-svg-XCjpVQJDV7HTnwqh .label text,#mermaid-svg-XCjpVQJDV7HTnwqh span{fill:#333;color:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh .node rect,#mermaid-svg-XCjpVQJDV7HTnwqh .node circle,#mermaid-svg-XCjpVQJDV7HTnwqh .node ellipse,#mermaid-svg-XCjpVQJDV7HTnwqh .node polygon,#mermaid-svg-XCjpVQJDV7HTnwqh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XCjpVQJDV7HTnwqh .rough-node .label text,#mermaid-svg-XCjpVQJDV7HTnwqh .node .label text,#mermaid-svg-XCjpVQJDV7HTnwqh .image-shape .label,#mermaid-svg-XCjpVQJDV7HTnwqh .icon-shape .label{text-anchor:middle;}#mermaid-svg-XCjpVQJDV7HTnwqh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XCjpVQJDV7HTnwqh .rough-node .label,#mermaid-svg-XCjpVQJDV7HTnwqh .node .label,#mermaid-svg-XCjpVQJDV7HTnwqh .image-shape .label,#mermaid-svg-XCjpVQJDV7HTnwqh .icon-shape .label{text-align:center;}#mermaid-svg-XCjpVQJDV7HTnwqh .node.clickable{cursor:pointer;}#mermaid-svg-XCjpVQJDV7HTnwqh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XCjpVQJDV7HTnwqh .arrowheadPath{fill:#333333;}#mermaid-svg-XCjpVQJDV7HTnwqh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XCjpVQJDV7HTnwqh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XCjpVQJDV7HTnwqh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XCjpVQJDV7HTnwqh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XCjpVQJDV7HTnwqh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XCjpVQJDV7HTnwqh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster text{fill:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh .cluster span{color:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XCjpVQJDV7HTnwqh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XCjpVQJDV7HTnwqh rect.text{fill:none;stroke-width:0;}#mermaid-svg-XCjpVQJDV7HTnwqh .icon-shape,#mermaid-svg-XCjpVQJDV7HTnwqh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XCjpVQJDV7HTnwqh .icon-shape p,#mermaid-svg-XCjpVQJDV7HTnwqh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XCjpVQJDV7HTnwqh .icon-shape .label rect,#mermaid-svg-XCjpVQJDV7HTnwqh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XCjpVQJDV7HTnwqh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XCjpVQJDV7HTnwqh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XCjpVQJDV7HTnwqh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Base62编码
存储映射
缓存加速
唯一数字ID
雪花算法
6位短码
8M0kX
MySQL
短码↔长URL
Redis
热点数据
2.1 分布式 ID 生成方案对比
生活化比喻:就像给全国每个人发唯一身份证号,有多种方案:
| 方案 | 原理 | 优点 | 缺点 | 推荐度 | 生活化比喻 |
|---|---|---|---|---|---|
| 雪花算法 | 时间戳 + 机器 ID + 序列号 | 高性能、趋势递增 | 依赖机器时钟 | ⭐⭐⭐⭐⭐ | 按"出生时间+出生地+顺序号"编号,趋势递增 |
| Leaf 号段模式 | 数据库预分配号段 | 实现简单、ID 连续 | 依赖数据库 | ⭐⭐⭐⭐ | 从户籍中心批量领号段,发完再领 |
| Redis INCR | 原子自增 | 性能高 | 持久化风险 | ⭐⭐⭐ | 用计数器,每次+1,简单高效 |
| UUID | 随机生成 | 本地生成、无依赖 | 无序、过长 | ⭐⭐ | 随机生成,全球唯一但太长 |
推荐方案:
- 中小规模:Redis INCR(简单高效,就像计数器)
- 大规模:雪花算法或 Leaf(美团开源,就像自动编号机)
2.2 Base62 编码原理
生活化比喻:
十进制用 0-9 十个数字(逢十进一)
十六进制用 0-9 + A-F(逢十六进一)
Base62 用 0-9 + a-z + A-Z 共 62 个字符(逢六十二进一)
就像:
十进制 10 → 十六进制 A
十进制 123456789 → Base62 "8M0kX"
好处:用更少的位数表示更大的数字
字符集 :0-9 + a-z + A-Z = 62 个字符
编码容量(就像算密码有多少种组合):
| 短码长度 | 容量 | 适用场景 | 生活化比喻 |
|---|---|---|---|
| 6 位 | 62⁶ ≈ 568 亿 | 超大规模(日活过亿) | 够全中国人每人分配 40 个 |
| 5 位 | 62⁵ ≈ 9.16 亿 | 大规模(千万级) | 够全中国人每人分配 0.7 个 |
| 4 位 | 62⁴ ≈ 1477 万 | 中等规模 | 够一个中等城市用 |
示例:
数字 ID: 123456789
Base62: 123456789 % 62 = 余数 → 查表 → 'd'
继续除 62...
最终结果: "8M0kX"
生活化比喻:
就像把 123456789 翻译成"外星语言",用 62 个字母表示。
优势:
- ✅ 天然唯一(依赖 ID 唯一性,就像身份证号唯一)
- ✅ 无碰撞(不需要重试,性能稳定)
- ✅ 短码可控(固定长度,不会越来越长)
- ✅ 高性能(纯计算,无 DB 查询,就像心算比查表快)
三、系统架构设计
3.1 整体架构图(全景视图)
生活化比喻:就像开一家快递公司
- 客户端:寄件人/收件人
- 负载均衡层:公司前台(限流、防刷,就像限制每人每天最多寄 100 个包裹)
- 短链接服务:分拣中心(处理生成和查询)
- 存储层:仓库(MySQL 持久化 + Redis 快速查找)
#mermaid-svg-yf29yU0jUX2HHYIf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yf29yU0jUX2HHYIf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yf29yU0jUX2HHYIf .error-icon{fill:#552222;}#mermaid-svg-yf29yU0jUX2HHYIf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yf29yU0jUX2HHYIf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yf29yU0jUX2HHYIf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yf29yU0jUX2HHYIf .marker.cross{stroke:#333333;}#mermaid-svg-yf29yU0jUX2HHYIf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yf29yU0jUX2HHYIf p{margin:0;}#mermaid-svg-yf29yU0jUX2HHYIf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yf29yU0jUX2HHYIf .cluster-label text{fill:#333;}#mermaid-svg-yf29yU0jUX2HHYIf .cluster-label span{color:#333;}#mermaid-svg-yf29yU0jUX2HHYIf .cluster-label span p{background-color:transparent;}#mermaid-svg-yf29yU0jUX2HHYIf .label text,#mermaid-svg-yf29yU0jUX2HHYIf span{fill:#333;color:#333;}#mermaid-svg-yf29yU0jUX2HHYIf .node rect,#mermaid-svg-yf29yU0jUX2HHYIf .node circle,#mermaid-svg-yf29yU0jUX2HHYIf .node ellipse,#mermaid-svg-yf29yU0jUX2HHYIf .node polygon,#mermaid-svg-yf29yU0jUX2HHYIf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yf29yU0jUX2HHYIf .rough-node .label text,#mermaid-svg-yf29yU0jUX2HHYIf .node .label text,#mermaid-svg-yf29yU0jUX2HHYIf .image-shape .label,#mermaid-svg-yf29yU0jUX2HHYIf .icon-shape .label{text-anchor:middle;}#mermaid-svg-yf29yU0jUX2HHYIf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yf29yU0jUX2HHYIf .rough-node .label,#mermaid-svg-yf29yU0jUX2HHYIf .node .label,#mermaid-svg-yf29yU0jUX2HHYIf .image-shape .label,#mermaid-svg-yf29yU0jUX2HHYIf .icon-shape .label{text-align:center;}#mermaid-svg-yf29yU0jUX2HHYIf .node.clickable{cursor:pointer;}#mermaid-svg-yf29yU0jUX2HHYIf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yf29yU0jUX2HHYIf .arrowheadPath{fill:#333333;}#mermaid-svg-yf29yU0jUX2HHYIf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yf29yU0jUX2HHYIf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yf29yU0jUX2HHYIf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yf29yU0jUX2HHYIf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yf29yU0jUX2HHYIf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yf29yU0jUX2HHYIf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yf29yU0jUX2HHYIf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yf29yU0jUX2HHYIf .cluster text{fill:#333;}#mermaid-svg-yf29yU0jUX2HHYIf .cluster span{color:#333;}#mermaid-svg-yf29yU0jUX2HHYIf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yf29yU0jUX2HHYIf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yf29yU0jUX2HHYIf rect.text{fill:none;stroke-width:0;}#mermaid-svg-yf29yU0jUX2HHYIf .icon-shape,#mermaid-svg-yf29yU0jUX2HHYIf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yf29yU0jUX2HHYIf .icon-shape p,#mermaid-svg-yf29yU0jUX2HHYIf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yf29yU0jUX2HHYIf .icon-shape .label rect,#mermaid-svg-yf29yU0jUX2HHYIf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yf29yU0jUX2HHYIf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yf29yU0jUX2HHYIf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yf29yU0jUX2HHYIf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 短链接服务集群
客户端请求
存储层
Redis缓存
MySQL持久化
布隆过滤器
读流程(短链跳转)
1.本地缓存Caffeine
4.布隆过滤器防穿透
2.Redis分布式缓存
3.MySQL回源查询
写流程(生成短链)
1.分布式发号器获取唯一ID
2.Base62编码生成短码
3.MySQL持久化映射关系
4.Redis缓存预热
负载均衡层 - Nginx
限流:令牌桶/漏桶
防刷:IP/用户维度
用户访问短链接
3.2 写流程详解(生成短链接)
生活化比喻:
就像给新员工发工号:
1. 从发号器拿一个唯一编号(分布式发号器)
2. 把编号翻译成短码(Base62 编码)
3. 把"短码 ↔ 长 URL"的映射关系记在花名册上(MySQL)
4. 同时更新到快速查询表上(Redis 预热)
5. 在门禁系统里登记(布隆过滤器)
布隆过滤器 Redis MySQL 分布式发号器 短链接服务 客户端 布隆过滤器 Redis MySQL 分布式发号器 短链接服务 客户端 #mermaid-svg-f67m8rNtdrhvRf7k{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-f67m8rNtdrhvRf7k .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-f67m8rNtdrhvRf7k .error-icon{fill:#552222;}#mermaid-svg-f67m8rNtdrhvRf7k .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-f67m8rNtdrhvRf7k .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-f67m8rNtdrhvRf7k .marker{fill:#333333;stroke:#333333;}#mermaid-svg-f67m8rNtdrhvRf7k .marker.cross{stroke:#333333;}#mermaid-svg-f67m8rNtdrhvRf7k svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-f67m8rNtdrhvRf7k p{margin:0;}#mermaid-svg-f67m8rNtdrhvRf7k .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-f67m8rNtdrhvRf7k text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-f67m8rNtdrhvRf7k .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-f67m8rNtdrhvRf7k .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-f67m8rNtdrhvRf7k .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-f67m8rNtdrhvRf7k .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-f67m8rNtdrhvRf7k #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-f67m8rNtdrhvRf7k .sequenceNumber{fill:white;}#mermaid-svg-f67m8rNtdrhvRf7k #sequencenumber{fill:#333;}#mermaid-svg-f67m8rNtdrhvRf7k #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-f67m8rNtdrhvRf7k .messageText{fill:#333;stroke:none;}#mermaid-svg-f67m8rNtdrhvRf7k .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-f67m8rNtdrhvRf7k .labelText,#mermaid-svg-f67m8rNtdrhvRf7k .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-f67m8rNtdrhvRf7k .loopText,#mermaid-svg-f67m8rNtdrhvRf7k .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-f67m8rNtdrhvRf7k .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-f67m8rNtdrhvRf7k .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-f67m8rNtdrhvRf7k .noteText,#mermaid-svg-f67m8rNtdrhvRf7k .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-f67m8rNtdrhvRf7k .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-f67m8rNtdrhvRf7k .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-f67m8rNtdrhvRf7k .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-f67m8rNtdrhvRf7k .actorPopupMenu{position:absolute;}#mermaid-svg-f67m8rNtdrhvRf7k .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-f67m8rNtdrhvRf7k .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-f67m8rNtdrhvRf7k .actor-man circle,#mermaid-svg-f67m8rNtdrhvRf7k line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-f67m8rNtdrhvRf7k :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 请求生成短链(longURL) 参数校验 & 限流检查 获取唯一ID 返回唯一ID (123456789) Base62编码 123456789 → "8M0kX" 插入映射关系 (shortCode, longURL, expireAt) 插入成功 缓存预热 SET shortCode longURL 缓存成功 添加到布隆过滤器 添加成功 返回短链接 http://t.cn/8M0kX
关键点:
- ✅ 分库分表 :按短码 Hash 分片(如
hash(shortCode) % 16),就像把花名册分成 16 本,查找更快 - ✅ 索引设计 :
short_code唯一索引 +long_url普通索引,就像给花名册建目录 - ✅ 异步写缓存:MySQL 成功后再写 Redis,失败可重试,就像先记在本子上,再录入电脑
3.3 读流程详解(短链跳转)
生活化比喻:
就像查电话号码:
1. 先查门禁系统,看这个人在不在公司(布隆过滤器)
2. 再查自己手机通讯录(本地缓存)
3. 再查公司通讯录(Redis)
4. 最后查户籍中心(MySQL)
找到后,把号码记在手机里(回写缓存),下次直接查手机。
MySQL Redis缓存 本地缓存 Caffeine 布隆过滤器 短链接服务 客户端 MySQL Redis缓存 本地缓存 Caffeine 布隆过滤器 短链接服务 客户端 #mermaid-svg-iTFNOa2SkRrFE3No{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iTFNOa2SkRrFE3No .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iTFNOa2SkRrFE3No .error-icon{fill:#552222;}#mermaid-svg-iTFNOa2SkRrFE3No .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iTFNOa2SkRrFE3No .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iTFNOa2SkRrFE3No .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iTFNOa2SkRrFE3No .marker.cross{stroke:#333333;}#mermaid-svg-iTFNOa2SkRrFE3No svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iTFNOa2SkRrFE3No p{margin:0;}#mermaid-svg-iTFNOa2SkRrFE3No .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iTFNOa2SkRrFE3No text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-iTFNOa2SkRrFE3No .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-iTFNOa2SkRrFE3No .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-iTFNOa2SkRrFE3No .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-iTFNOa2SkRrFE3No .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-iTFNOa2SkRrFE3No #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-iTFNOa2SkRrFE3No .sequenceNumber{fill:white;}#mermaid-svg-iTFNOa2SkRrFE3No #sequencenumber{fill:#333;}#mermaid-svg-iTFNOa2SkRrFE3No #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-iTFNOa2SkRrFE3No .messageText{fill:#333;stroke:none;}#mermaid-svg-iTFNOa2SkRrFE3No .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iTFNOa2SkRrFE3No .labelText,#mermaid-svg-iTFNOa2SkRrFE3No .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-iTFNOa2SkRrFE3No .loopText,#mermaid-svg-iTFNOa2SkRrFE3No .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-iTFNOa2SkRrFE3No .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-iTFNOa2SkRrFE3No .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-iTFNOa2SkRrFE3No .noteText,#mermaid-svg-iTFNOa2SkRrFE3No .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-iTFNOa2SkRrFE3No .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iTFNOa2SkRrFE3No .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iTFNOa2SkRrFE3No .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iTFNOa2SkRrFE3No .actorPopupMenu{position:absolute;}#mermaid-svg-iTFNOa2SkRrFE3No .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-iTFNOa2SkRrFE3No .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iTFNOa2SkRrFE3No .actor-man circle,#mermaid-svg-iTFNOa2SkRrFE3No line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-iTFNOa2SkRrFE3No :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 缓存未命中场景 访问短链接(/8M0kX) 查询布隆过滤器 可能存在(99%准确) 查询本地缓存 未命中 查询Redis 命中(80-90%) 回写本地缓存 302重定向到长链接 查询MySQL 返回长链接 回写Redis(TTL 24h) 回写本地缓存(TTL 5min) 302重定向到长链接
缓存穿透防护(什么是"穿透"?):
生活化比喻:
缓存穿透就像:你问前台"张三在哪个部门?",前台说"没有这个人"。
但你不确定,又去问 HR,HR 也说"没有"。
这就是"穿透"了缓存,直接查到了数据库。
防护方案:
1. 布隆过滤器:拦截 99% 的不存在短码(就像门禁系统,不在名单上直接拦住)
2. 空值缓存:MySQL 查询为空也缓存(TTL 5 分钟),下次直接返回"不存在"
四、面试高频考点:301 vs 302 重定向
核心对比(生活化理解)
生活化比喻:
301 永久重定向:
就像你搬家了,告诉邮局"我的新地址是 XXX,以后所有信件直接送到新地址"。
邮局会记住这个变化,以后不再问你了。
优点:邮局轻松(服务端压力小)
缺点:你无法统计有多少人给你写信了(无法统计点击)
302 临时重定向:
就像你出差了,告诉邮局"这周信件转寄到 XXX"。
每次有信件,邮局都会问你"转寄到哪里?"
优点:你可以统计有多少信件(可统计点击)
缺点:邮局每次都来问你(每次经过服务端)
#mermaid-svg-5FrAfDDTiS7I3y30{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5FrAfDDTiS7I3y30 .error-icon{fill:#552222;}#mermaid-svg-5FrAfDDTiS7I3y30 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5FrAfDDTiS7I3y30 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5FrAfDDTiS7I3y30 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5FrAfDDTiS7I3y30 .marker.cross{stroke:#333333;}#mermaid-svg-5FrAfDDTiS7I3y30 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5FrAfDDTiS7I3y30 p{margin:0;}#mermaid-svg-5FrAfDDTiS7I3y30 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster-label text{fill:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster-label span{color:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster-label span p{background-color:transparent;}#mermaid-svg-5FrAfDDTiS7I3y30 .label text,#mermaid-svg-5FrAfDDTiS7I3y30 span{fill:#333;color:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 .node rect,#mermaid-svg-5FrAfDDTiS7I3y30 .node circle,#mermaid-svg-5FrAfDDTiS7I3y30 .node ellipse,#mermaid-svg-5FrAfDDTiS7I3y30 .node polygon,#mermaid-svg-5FrAfDDTiS7I3y30 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5FrAfDDTiS7I3y30 .rough-node .label text,#mermaid-svg-5FrAfDDTiS7I3y30 .node .label text,#mermaid-svg-5FrAfDDTiS7I3y30 .image-shape .label,#mermaid-svg-5FrAfDDTiS7I3y30 .icon-shape .label{text-anchor:middle;}#mermaid-svg-5FrAfDDTiS7I3y30 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5FrAfDDTiS7I3y30 .rough-node .label,#mermaid-svg-5FrAfDDTiS7I3y30 .node .label,#mermaid-svg-5FrAfDDTiS7I3y30 .image-shape .label,#mermaid-svg-5FrAfDDTiS7I3y30 .icon-shape .label{text-align:center;}#mermaid-svg-5FrAfDDTiS7I3y30 .node.clickable{cursor:pointer;}#mermaid-svg-5FrAfDDTiS7I3y30 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5FrAfDDTiS7I3y30 .arrowheadPath{fill:#333333;}#mermaid-svg-5FrAfDDTiS7I3y30 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5FrAfDDTiS7I3y30 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5FrAfDDTiS7I3y30 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FrAfDDTiS7I3y30 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5FrAfDDTiS7I3y30 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FrAfDDTiS7I3y30 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster text{fill:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 .cluster span{color:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5FrAfDDTiS7I3y30 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5FrAfDDTiS7I3y30 rect.text{fill:none;stroke-width:0;}#mermaid-svg-5FrAfDDTiS7I3y30 .icon-shape,#mermaid-svg-5FrAfDDTiS7I3y30 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FrAfDDTiS7I3y30 .icon-shape p,#mermaid-svg-5FrAfDDTiS7I3y30 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5FrAfDDTiS7I3y30 .icon-shape .label rect,#mermaid-svg-5FrAfDDTiS7I3y30 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FrAfDDTiS7I3y30 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5FrAfDDTiS7I3y30 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5FrAfDDTiS7I3y30 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 302 临时重定向
用户访问短链
服务端处理
统计点击/UV
可修改目标
302重定向
跳转到长链
每次经过服务端
301 永久重定向
后续请求
用户访问短链
浏览器缓存
直接跳转长链
服务端压力小
无法统计点击
不可修改目标
| 特性 | 301 永久重定向 | 302 临时重定向 |
|---|---|---|
| 缓存行为 | 浏览器本地缓存跳转 | 每次都请求服务端 |
| 性能 | ⭐⭐⭐⭐⭐(无服务端压力) | ⭐⭐⭐(所有流量到后端) |
| 可修改性 | ❌ 无法修改目标 URL | ✅ 可随时修改目标 URL |
| 数据统计 | ❌ 无法统计点击量 | ✅ 可统计点击、UV、PV |
| 适用场景 | 链接永久不变 | 需要统计/动态修改 |
| 生产使用 | 较少 | 更常用 ⭐⭐⭐⭐⭐ |
面试话术模板(直接背诵版)
标准回答(30 秒版):
"短链接跳转我建议选择 302 临时重定向,原因是:
- 业务需求:大多数短链接系统需要统计点击量、UV、地域分布等数据,302 每次请求都经过服务端,方便做埋点统计。
- 灵活性:后期可以修改短链接的目标 URL,比如活动页面变更,301 则无法修改。
- 并发压力 :302 的缺点是 All 流量都打到后端,需要通过本地缓存 + Redis + 布隆过滤器来扛住高并发。
如果业务明确不需要统计(如永久资源链接),可以选择 301,直接在 Nginx 层配置跳转,性能更高。"
加分回答(展示深度):
"实际生产中,我们可以做混合方案:
- 对于热点短链(访问频率 > 1000 次/秒),使用 301 + CDN 缓存,减轻服务端压力。
- 对于普通短链,使用 302,保证数据统计能力。
- 这样既兼顾性能,又满足业务需求。"
面试官追问:那如何识别热点短链?
"可以用 Redis 的 ZSET 记录每个短链的访问次数,超过阈值就标记为热点。同时用本地缓存(Caffeine/GoCache)缓存热点数据,抗 10 万+ QPS。"
五、高并发优化方案
5.1 多级缓存架构
生活化比喻:
多级缓存就像找信息的三个层次:
L1 本地缓存:就像你的手机通讯录(最快,但容量小)
L2 Redis 缓存:就像公司通讯录(快,容量中等)
L3 MySQL:就像户籍中心(慢,但容量大,永久保存)
热点数据(明星微博):
瞬间 10 万 QPS,就像 10 万人同时问"小明的电话是多少?"
如果每次都查户籍中心,户籍中心就挂了。
所以:
- 本地缓存:直接查手机(零网络 IO,抗 10 万+ QPS)
- Redis:查公司通讯录(快,但扛不住 10 万 QPS)
- MySQL:最后手段(慢,但可靠)
#mermaid-svg-2rsLYWoLIIRfa7cJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2rsLYWoLIIRfa7cJ .error-icon{fill:#552222;}#mermaid-svg-2rsLYWoLIIRfa7cJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2rsLYWoLIIRfa7cJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .marker.cross{stroke:#333333;}#mermaid-svg-2rsLYWoLIIRfa7cJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2rsLYWoLIIRfa7cJ p{margin:0;}#mermaid-svg-2rsLYWoLIIRfa7cJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster-label text{fill:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster-label span{color:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster-label span p{background-color:transparent;}#mermaid-svg-2rsLYWoLIIRfa7cJ .label text,#mermaid-svg-2rsLYWoLIIRfa7cJ span{fill:#333;color:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .node rect,#mermaid-svg-2rsLYWoLIIRfa7cJ .node circle,#mermaid-svg-2rsLYWoLIIRfa7cJ .node ellipse,#mermaid-svg-2rsLYWoLIIRfa7cJ .node polygon,#mermaid-svg-2rsLYWoLIIRfa7cJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .rough-node .label text,#mermaid-svg-2rsLYWoLIIRfa7cJ .node .label text,#mermaid-svg-2rsLYWoLIIRfa7cJ .image-shape .label,#mermaid-svg-2rsLYWoLIIRfa7cJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-2rsLYWoLIIRfa7cJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .rough-node .label,#mermaid-svg-2rsLYWoLIIRfa7cJ .node .label,#mermaid-svg-2rsLYWoLIIRfa7cJ .image-shape .label,#mermaid-svg-2rsLYWoLIIRfa7cJ .icon-shape .label{text-align:center;}#mermaid-svg-2rsLYWoLIIRfa7cJ .node.clickable{cursor:pointer;}#mermaid-svg-2rsLYWoLIIRfa7cJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .arrowheadPath{fill:#333333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2rsLYWoLIIRfa7cJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2rsLYWoLIIRfa7cJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2rsLYWoLIIRfa7cJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster text{fill:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ .cluster span{color:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2rsLYWoLIIRfa7cJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2rsLYWoLIIRfa7cJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-2rsLYWoLIIRfa7cJ .icon-shape,#mermaid-svg-2rsLYWoLIIRfa7cJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2rsLYWoLIIRfa7cJ .icon-shape p,#mermaid-svg-2rsLYWoLIIRfa7cJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2rsLYWoLIIRfa7cJ .icon-shape .label rect,#mermaid-svg-2rsLYWoLIIRfa7cJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2rsLYWoLIIRfa7cJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2rsLYWoLIIRfa7cJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2rsLYWoLIIRfa7cJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 可能存在
未命中
未命中
查到
防护层
布隆过滤器
拦截99%不存在短码
L3: 持久化存储
MySQL分库分表
永久存储
命中率: <5%
L2: 分布式缓存
Redis Cluster
TTL: 24小时
命中率: 80-90%
L1: 本地缓存
Caffeine/GoCache
TTL: 5分钟
命中率: 10-20%
请求短链
场景:某个短链突然爆火(如明星微博),瞬间 10 万 QPS。
本地缓存优势:
- ✅ 零网络 IO(进程内存直接返回,就像查手机通讯录,不用联网)
- ✅ 抗热点(单节点可扛 10 万+ QPS,就像你一个人能回答 10 万人的问题)
- ✅ 减轻 Redis 压力(Redis 挂了也不怕,本地缓存还能撑一会)
代码示例(Go 语言版):
go
// 多级缓存架构
type MultiLevelCache struct {
localCache *cache.Cache // Caffeine/GoCache(本地缓存)
redisCache *redis.Client // Redis(分布式缓存)
mysqlDB *gorm.DB // MySQL(持久化存储)
bloomFilter *bloom.BloomFilter // 布隆过滤器(防穿透)
}
func (c *MultiLevelCache) Get(shortCode string) (string, error) {
// L1: 本地缓存(最快,像查手机通讯录)
if val, ok := c.localCache.Get(shortCode); ok {
return val, nil
}
// L2: Redis(快,像查公司通讯录)
val, err := c.redisCache.Get(shortCode).Result()
if err == nil {
c.localCache.Set(shortCode, val, 5*time.Minute) // 回写本地
return val, nil
}
// L3: MySQL(慢,但可靠,像查户籍中心)
mapping, err := c.mysqlDB.Query(shortCode)
if err == nil {
c.redisCache.Set(shortCode, mapping.LongURL, 24*time.Hour)
c.localCache.Set(shortCode, mapping.LongURL, 5*time.Minute)
return mapping.LongURL, nil
}
return "", errors.New("not found")
}
5.2 分库分表策略
生活化比喻:
分库分表就像把一本大花名册分成多本小册子:
- 按短码分:把所有"张"姓放在一本,"李"姓放在另一本
- 按用户分:把北京用户放在一本,上海用户放在另一本
好处:查找时不用翻整本大册子,只查对应的小册子,速度快。
#mermaid-svg-Bpjb83tYScHjssev{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Bpjb83tYScHjssev .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Bpjb83tYScHjssev .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Bpjb83tYScHjssev .error-icon{fill:#552222;}#mermaid-svg-Bpjb83tYScHjssev .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Bpjb83tYScHjssev .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Bpjb83tYScHjssev .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Bpjb83tYScHjssev .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Bpjb83tYScHjssev .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Bpjb83tYScHjssev .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Bpjb83tYScHjssev .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Bpjb83tYScHjssev .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Bpjb83tYScHjssev .marker.cross{stroke:#333333;}#mermaid-svg-Bpjb83tYScHjssev svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Bpjb83tYScHjssev p{margin:0;}#mermaid-svg-Bpjb83tYScHjssev .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Bpjb83tYScHjssev .cluster-label text{fill:#333;}#mermaid-svg-Bpjb83tYScHjssev .cluster-label span{color:#333;}#mermaid-svg-Bpjb83tYScHjssev .cluster-label span p{background-color:transparent;}#mermaid-svg-Bpjb83tYScHjssev .label text,#mermaid-svg-Bpjb83tYScHjssev span{fill:#333;color:#333;}#mermaid-svg-Bpjb83tYScHjssev .node rect,#mermaid-svg-Bpjb83tYScHjssev .node circle,#mermaid-svg-Bpjb83tYScHjssev .node ellipse,#mermaid-svg-Bpjb83tYScHjssev .node polygon,#mermaid-svg-Bpjb83tYScHjssev .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Bpjb83tYScHjssev .rough-node .label text,#mermaid-svg-Bpjb83tYScHjssev .node .label text,#mermaid-svg-Bpjb83tYScHjssev .image-shape .label,#mermaid-svg-Bpjb83tYScHjssev .icon-shape .label{text-anchor:middle;}#mermaid-svg-Bpjb83tYScHjssev .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Bpjb83tYScHjssev .rough-node .label,#mermaid-svg-Bpjb83tYScHjssev .node .label,#mermaid-svg-Bpjb83tYScHjssev .image-shape .label,#mermaid-svg-Bpjb83tYScHjssev .icon-shape .label{text-align:center;}#mermaid-svg-Bpjb83tYScHjssev .node.clickable{cursor:pointer;}#mermaid-svg-Bpjb83tYScHjssev .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Bpjb83tYScHjssev .arrowheadPath{fill:#333333;}#mermaid-svg-Bpjb83tYScHjssev .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Bpjb83tYScHjssev .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Bpjb83tYScHjssev .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bpjb83tYScHjssev .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Bpjb83tYScHjssev .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bpjb83tYScHjssev .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Bpjb83tYScHjssev .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Bpjb83tYScHjssev .cluster text{fill:#333;}#mermaid-svg-Bpjb83tYScHjssev .cluster span{color:#333;}#mermaid-svg-Bpjb83tYScHjssev div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Bpjb83tYScHjssev .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Bpjb83tYScHjssev rect.text{fill:none;stroke-width:0;}#mermaid-svg-Bpjb83tYScHjssev .icon-shape,#mermaid-svg-Bpjb83tYScHjssev .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bpjb83tYScHjssev .icon-shape p,#mermaid-svg-Bpjb83tYScHjssev .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Bpjb83tYScHjssev .icon-shape .label rect,#mermaid-svg-Bpjb83tYScHjssev .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bpjb83tYScHjssev .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Bpjb83tYScHjssev .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Bpjb83tYScHjssev :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Hash计算
Hash计算
短码: 8M0kX
hash 8M0kX % 16
分片 0-15
库 3
表 067
用户ID: 12345
hash 12345 % 8
分片 0-7
库 5
表 123
分片规则:
| 维度 | 规则 | 适用场景 | 生活化比喻 |
|---|---|---|---|
| 短码 Hash | hash(shortCode) % 16 |
按短码查询(跳转场景) | 按姓氏分花名册 |
| 用户 ID | userID % 8 |
按用户查询(管理场景) | 按地区分花名册 |
表结构设计:
sql
CREATE TABLE url_mapping_0 (
id BIGINT PRIMARY KEY,
short_code VARCHAR(10) UNIQUE NOT NULL, -- 短码(唯一)
long_url VARCHAR(2048) NOT NULL, -- 长 URL
user_id BIGINT NOT NULL, -- 用户 ID
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expire_at TIMESTAMP, -- 过期时间
status TINYINT DEFAULT 1, -- 1:有效 0:失效
INDEX idx_user_id (user_id), -- 按用户查询
INDEX idx_expire (expire_at) -- 按过期时间清理
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.3 过期数据清理
生活化比喻:
过期数据清理就像清理过期的食品:
方案1:定期大扫除(定时任务)
每天凌晨 2 点,把过期食品扔掉(分批扔,别把垃圾桶撑爆)
方案2:随手清理(延迟删除)
每次拿食品时,看看过期没,过期就扔掉
方案3:按月份分区(分区表)
把食品按月份放在不同房间,过期了整个房间一起清空
#mermaid-svg-qULJKkSyGAb5lpvi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qULJKkSyGAb5lpvi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qULJKkSyGAb5lpvi .error-icon{fill:#552222;}#mermaid-svg-qULJKkSyGAb5lpvi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qULJKkSyGAb5lpvi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qULJKkSyGAb5lpvi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qULJKkSyGAb5lpvi .marker.cross{stroke:#333333;}#mermaid-svg-qULJKkSyGAb5lpvi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qULJKkSyGAb5lpvi p{margin:0;}#mermaid-svg-qULJKkSyGAb5lpvi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qULJKkSyGAb5lpvi .cluster-label text{fill:#333;}#mermaid-svg-qULJKkSyGAb5lpvi .cluster-label span{color:#333;}#mermaid-svg-qULJKkSyGAb5lpvi .cluster-label span p{background-color:transparent;}#mermaid-svg-qULJKkSyGAb5lpvi .label text,#mermaid-svg-qULJKkSyGAb5lpvi span{fill:#333;color:#333;}#mermaid-svg-qULJKkSyGAb5lpvi .node rect,#mermaid-svg-qULJKkSyGAb5lpvi .node circle,#mermaid-svg-qULJKkSyGAb5lpvi .node ellipse,#mermaid-svg-qULJKkSyGAb5lpvi .node polygon,#mermaid-svg-qULJKkSyGAb5lpvi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qULJKkSyGAb5lpvi .rough-node .label text,#mermaid-svg-qULJKkSyGAb5lpvi .node .label text,#mermaid-svg-qULJKkSyGAb5lpvi .image-shape .label,#mermaid-svg-qULJKkSyGAb5lpvi .icon-shape .label{text-anchor:middle;}#mermaid-svg-qULJKkSyGAb5lpvi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qULJKkSyGAb5lpvi .rough-node .label,#mermaid-svg-qULJKkSyGAb5lpvi .node .label,#mermaid-svg-qULJKkSyGAb5lpvi .image-shape .label,#mermaid-svg-qULJKkSyGAb5lpvi .icon-shape .label{text-align:center;}#mermaid-svg-qULJKkSyGAb5lpvi .node.clickable{cursor:pointer;}#mermaid-svg-qULJKkSyGAb5lpvi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qULJKkSyGAb5lpvi .arrowheadPath{fill:#333333;}#mermaid-svg-qULJKkSyGAb5lpvi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qULJKkSyGAb5lpvi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qULJKkSyGAb5lpvi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qULJKkSyGAb5lpvi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qULJKkSyGAb5lpvi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qULJKkSyGAb5lpvi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qULJKkSyGAb5lpvi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qULJKkSyGAb5lpvi .cluster text{fill:#333;}#mermaid-svg-qULJKkSyGAb5lpvi .cluster span{color:#333;}#mermaid-svg-qULJKkSyGAb5lpvi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qULJKkSyGAb5lpvi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qULJKkSyGAb5lpvi rect.text{fill:none;stroke-width:0;}#mermaid-svg-qULJKkSyGAb5lpvi .icon-shape,#mermaid-svg-qULJKkSyGAb5lpvi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qULJKkSyGAb5lpvi .icon-shape p,#mermaid-svg-qULJKkSyGAb5lpvi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qULJKkSyGAb5lpvi .icon-shape .label rect,#mermaid-svg-qULJKkSyGAb5lpvi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qULJKkSyGAb5lpvi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qULJKkSyGAb5lpvi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qULJKkSyGAb5lpvi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 策略3: 分区表
按月分区
2024-01分区
2024-02分区
2024-03分区
过期直接Drop Partition
策略2: 延迟删除
是
否
访问短链
是否过期?
返回404
异步删除记录
正常跳转
策略1: 定时任务
每天凌晨2点
扫描过期数据
批量删除 LIMIT 10000
分批删除避免锁表
SQL 示例:
sql
-- 定时清理任务(分批删除,别把数据库锁死)
DELETE FROM url_mapping
WHERE expire_at < NOW()
LIMIT 10000;
5.4 限流与防刷
生活化比喻:
限流就像餐厅限制每人最多点 10 道菜:
- 用户维度:每人每小时最多生成 100 个短链(防恶意生成)
- IP 维度:每个 IP 每分钟最多 1000 次请求(防 DDOS)
- 接口维度:整个系统最多 10000 QPS(保护后端)
限流算法:
- 令牌桶:允许突发流量(像水桶,水满了可以一次性倒很多)
- 漏桶:平滑流量(像漏斗,水流得很均匀)
#mermaid-svg-bM5276Fun6OL2wnp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bM5276Fun6OL2wnp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bM5276Fun6OL2wnp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bM5276Fun6OL2wnp .error-icon{fill:#552222;}#mermaid-svg-bM5276Fun6OL2wnp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bM5276Fun6OL2wnp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bM5276Fun6OL2wnp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bM5276Fun6OL2wnp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bM5276Fun6OL2wnp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bM5276Fun6OL2wnp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bM5276Fun6OL2wnp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bM5276Fun6OL2wnp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bM5276Fun6OL2wnp .marker.cross{stroke:#333333;}#mermaid-svg-bM5276Fun6OL2wnp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bM5276Fun6OL2wnp p{margin:0;}#mermaid-svg-bM5276Fun6OL2wnp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bM5276Fun6OL2wnp .cluster-label text{fill:#333;}#mermaid-svg-bM5276Fun6OL2wnp .cluster-label span{color:#333;}#mermaid-svg-bM5276Fun6OL2wnp .cluster-label span p{background-color:transparent;}#mermaid-svg-bM5276Fun6OL2wnp .label text,#mermaid-svg-bM5276Fun6OL2wnp span{fill:#333;color:#333;}#mermaid-svg-bM5276Fun6OL2wnp .node rect,#mermaid-svg-bM5276Fun6OL2wnp .node circle,#mermaid-svg-bM5276Fun6OL2wnp .node ellipse,#mermaid-svg-bM5276Fun6OL2wnp .node polygon,#mermaid-svg-bM5276Fun6OL2wnp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bM5276Fun6OL2wnp .rough-node .label text,#mermaid-svg-bM5276Fun6OL2wnp .node .label text,#mermaid-svg-bM5276Fun6OL2wnp .image-shape .label,#mermaid-svg-bM5276Fun6OL2wnp .icon-shape .label{text-anchor:middle;}#mermaid-svg-bM5276Fun6OL2wnp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bM5276Fun6OL2wnp .rough-node .label,#mermaid-svg-bM5276Fun6OL2wnp .node .label,#mermaid-svg-bM5276Fun6OL2wnp .image-shape .label,#mermaid-svg-bM5276Fun6OL2wnp .icon-shape .label{text-align:center;}#mermaid-svg-bM5276Fun6OL2wnp .node.clickable{cursor:pointer;}#mermaid-svg-bM5276Fun6OL2wnp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bM5276Fun6OL2wnp .arrowheadPath{fill:#333333;}#mermaid-svg-bM5276Fun6OL2wnp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bM5276Fun6OL2wnp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bM5276Fun6OL2wnp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bM5276Fun6OL2wnp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bM5276Fun6OL2wnp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bM5276Fun6OL2wnp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bM5276Fun6OL2wnp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bM5276Fun6OL2wnp .cluster text{fill:#333;}#mermaid-svg-bM5276Fun6OL2wnp .cluster span{color:#333;}#mermaid-svg-bM5276Fun6OL2wnp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bM5276Fun6OL2wnp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bM5276Fun6OL2wnp rect.text{fill:none;stroke-width:0;}#mermaid-svg-bM5276Fun6OL2wnp .icon-shape,#mermaid-svg-bM5276Fun6OL2wnp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bM5276Fun6OL2wnp .icon-shape p,#mermaid-svg-bM5276Fun6OL2wnp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bM5276Fun6OL2wnp .icon-shape .label rect,#mermaid-svg-bM5276Fun6OL2wnp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bM5276Fun6OL2wnp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bM5276Fun6OL2wnp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bM5276Fun6OL2wnp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 通过
拒绝
限流算法对比
允许突发
平滑流量
令牌桶
适合读多写少
漏桶
严格限流
多维度限流
100次/小时
1000次/分钟
10000QPS
用户维度
防恶意生成
IP维度
防DDOS
接口维度
保护后端
请求
短链服务
返回429
六、面试追问与深度问题
#mermaid-svg-mpT3ZfVZA9ITVw4S{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mpT3ZfVZA9ITVw4S .error-icon{fill:#552222;}#mermaid-svg-mpT3ZfVZA9ITVw4S .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mpT3ZfVZA9ITVw4S .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .marker.cross{stroke:#333333;}#mermaid-svg-mpT3ZfVZA9ITVw4S svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mpT3ZfVZA9ITVw4S p{margin:0;}#mermaid-svg-mpT3ZfVZA9ITVw4S .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster-label text{fill:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster-label span{color:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster-label span p{background-color:transparent;}#mermaid-svg-mpT3ZfVZA9ITVw4S .label text,#mermaid-svg-mpT3ZfVZA9ITVw4S span{fill:#333;color:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .node rect,#mermaid-svg-mpT3ZfVZA9ITVw4S .node circle,#mermaid-svg-mpT3ZfVZA9ITVw4S .node ellipse,#mermaid-svg-mpT3ZfVZA9ITVw4S .node polygon,#mermaid-svg-mpT3ZfVZA9ITVw4S .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .rough-node .label text,#mermaid-svg-mpT3ZfVZA9ITVw4S .node .label text,#mermaid-svg-mpT3ZfVZA9ITVw4S .image-shape .label,#mermaid-svg-mpT3ZfVZA9ITVw4S .icon-shape .label{text-anchor:middle;}#mermaid-svg-mpT3ZfVZA9ITVw4S .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .rough-node .label,#mermaid-svg-mpT3ZfVZA9ITVw4S .node .label,#mermaid-svg-mpT3ZfVZA9ITVw4S .image-shape .label,#mermaid-svg-mpT3ZfVZA9ITVw4S .icon-shape .label{text-align:center;}#mermaid-svg-mpT3ZfVZA9ITVw4S .node.clickable{cursor:pointer;}#mermaid-svg-mpT3ZfVZA9ITVw4S .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .arrowheadPath{fill:#333333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mpT3ZfVZA9ITVw4S .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mpT3ZfVZA9ITVw4S .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mpT3ZfVZA9ITVw4S .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster text{fill:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S .cluster span{color:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mpT3ZfVZA9ITVw4S .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mpT3ZfVZA9ITVw4S rect.text{fill:none;stroke-width:0;}#mermaid-svg-mpT3ZfVZA9ITVw4S .icon-shape,#mermaid-svg-mpT3ZfVZA9ITVw4S .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mpT3ZfVZA9ITVw4S .icon-shape p,#mermaid-svg-mpT3ZfVZA9ITVw4S .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mpT3ZfVZA9ITVw4S .icon-shape .label rect,#mermaid-svg-mpT3ZfVZA9ITVw4S .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mpT3ZfVZA9ITVw4S .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mpT3ZfVZA9ITVw4S .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mpT3ZfVZA9ITVw4S :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Q5: 点击量统计?
实时统计
Redis INCR
异步统计
MQ消息
消费者写入统计库
CDN统计
CDN日志分析
Q4: 布隆过滤器误判?
误判: 误认为存在
查MySQL
查不到返回404
调整参数
比特数组大小
Hash函数数量
控制误判率<1%
Q3: 容量规划?
日活1000万
每人5个/天
5000万/天
6位Base62容量568亿
可支撑8年
存储2.5GB/天
Q2: 相同长URL重复生成?
方案1: 允许重复
每次新短码
方案2: 去重优化
先查长URL是否存在
存在返回旧短码
需加分布式锁
Q1: 如何保证短码唯一性?
分布式发号器
雪花算法
时间戳+机器ID+序列号
全局唯一
Base62确定性映射
无碰撞
详细回答(面试话术)
Q1: 如何保证短码的唯一性?
答:依赖分布式发号器的唯一性。雪花算法通过时间戳 + 机器 ID + 序列号保证全局唯一(就像身份证号),Base62 编码是确定性映射(123456789 永远翻译成 "8M0kX"),不会产生碰撞。
Q2: 如果两个用户同时生成同一个长 URL 的短链,怎么办?
答:两种方案:
- 允许重复:每次生成新的短码(简单,但浪费存储,就像给同一个人发两张不同的名片)
- 去重优化:先查长 URL 是否已存在,存在则返回旧短码(需加分布式锁,就像先查花名册,看这个人在不在)
Q3: 短链接系统如何做容量规划?
答:
- 日活 1000 万,每人每天生成 5 个短链 → 5000 万/天
- 6 位 Base62 容量 568 亿,可支撑 3000+ 天(约 8 年),就像一个大仓库,够装 8 年的货物
- 存储:50 字节/条 × 5000 万 = 2.5 GB/天
- MySQL 分 16 库,每库每天 150 MB,完全可控
Q4: 布隆过滤器的误判率如何处理?
答:布隆过滤器有误判(可能误认为存在,但不会误认为不存在),处理方案:
- 误判时查 MySQL,查不到返回 404(就像门禁系统放你进去了,但办公室发现你不在)
- 调整比特数组大小和 Hash 函数数量,控制误判率 < 1%
- 定期重建(删除过期数据后)
Q5: 如何统计短链接的点击量?
答:
- 实时统计:每次跳转写 Redis(INCR 命令),就像计数器
- 异步统计:跳转时发 MQ 消息,消费者异步写入统计库(不阻塞主流程)
- CDN 统计:如果用 CDN,可直接看 CDN 日志(最准确)
七、面试回答提纲(30 秒版)
#mermaid-svg-NaJUXjM6bviGTxwQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NaJUXjM6bviGTxwQ .error-icon{fill:#552222;}#mermaid-svg-NaJUXjM6bviGTxwQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NaJUXjM6bviGTxwQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NaJUXjM6bviGTxwQ .marker.cross{stroke:#333333;}#mermaid-svg-NaJUXjM6bviGTxwQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NaJUXjM6bviGTxwQ p{margin:0;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge{stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 text{fill:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth--1{stroke-width:17;}#mermaid-svg-NaJUXjM6bviGTxwQ .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-0{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-0{stroke-width:14;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-1{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-1{stroke-width:11;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 text{fill:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-2{stroke-width:8;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-3{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-3{stroke-width:5;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-4{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-4{stroke-width:2;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-5{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-5{stroke-width:-1;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-6{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-6{stroke-width:-4;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-7{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-7{stroke-width:-7;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-8{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-8{stroke-width:-10;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-9{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-9{stroke-width:-13;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 polygon,#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 text{fill:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .node-icon-10{font-size:40px;color:black;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .edge-depth-10{stroke-width:-16;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled circle,#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:lightgray;}#mermaid-svg-NaJUXjM6bviGTxwQ .disabled text{fill:#efefef;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-root rect,#mermaid-svg-NaJUXjM6bviGTxwQ .section-root path,#mermaid-svg-NaJUXjM6bviGTxwQ .section-root circle,#mermaid-svg-NaJUXjM6bviGTxwQ .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-NaJUXjM6bviGTxwQ .section-root text{fill:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-root span{color:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .section-2 span{color:#ffffff;}#mermaid-svg-NaJUXjM6bviGTxwQ .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-NaJUXjM6bviGTxwQ .edge{fill:none;}#mermaid-svg-NaJUXjM6bviGTxwQ .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-NaJUXjM6bviGTxwQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 短链接系统
业务特点
读多写少 100:1
核心难点
短码唯一
跳转低延迟
扛高并发
短码生成
不用MD5 有碰撞
分布式发号器
Base62编码
存储层
MySQL分库分表
Redis热点缓存
布隆过滤器防穿透
跳转优化
302临时重定向
方便统计点击
三级缓存
高并发优化
本地缓存Caffeine
接口层限流防刷
过期清理
标准回答模板(直接背诵):
业务特点 :读多写少(100:1),核心难点是短码唯一、跳转低延迟、扛高并发。
短码生成 :不用 MD5(有碰撞),用分布式发号器 + Base62 编码,保证天然唯一、无碰撞。
存储层:MySQL 分库分表持久化,Redis 做热点缓存,布隆过滤器防穿透。
跳转优化 :用 302 临时重定向(方便统计),通过本地缓存 + Redis + MySQL三级缓存扛并发。
高并发:热点短链用本地缓存(Caffeine),抗 10 万+ QPS;接口层限流防刷。
八、生产环境 Checklist(部署检查清单)
#mermaid-svg-fSYPfulwMYR9gkVl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fSYPfulwMYR9gkVl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fSYPfulwMYR9gkVl .error-icon{fill:#552222;}#mermaid-svg-fSYPfulwMYR9gkVl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fSYPfulwMYR9gkVl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fSYPfulwMYR9gkVl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fSYPfulwMYR9gkVl .marker.cross{stroke:#333333;}#mermaid-svg-fSYPfulwMYR9gkVl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fSYPfulwMYR9gkVl p{margin:0;}#mermaid-svg-fSYPfulwMYR9gkVl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fSYPfulwMYR9gkVl .cluster-label text{fill:#333;}#mermaid-svg-fSYPfulwMYR9gkVl .cluster-label span{color:#333;}#mermaid-svg-fSYPfulwMYR9gkVl .cluster-label span p{background-color:transparent;}#mermaid-svg-fSYPfulwMYR9gkVl .label text,#mermaid-svg-fSYPfulwMYR9gkVl span{fill:#333;color:#333;}#mermaid-svg-fSYPfulwMYR9gkVl .node rect,#mermaid-svg-fSYPfulwMYR9gkVl .node circle,#mermaid-svg-fSYPfulwMYR9gkVl .node ellipse,#mermaid-svg-fSYPfulwMYR9gkVl .node polygon,#mermaid-svg-fSYPfulwMYR9gkVl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fSYPfulwMYR9gkVl .rough-node .label text,#mermaid-svg-fSYPfulwMYR9gkVl .node .label text,#mermaid-svg-fSYPfulwMYR9gkVl .image-shape .label,#mermaid-svg-fSYPfulwMYR9gkVl .icon-shape .label{text-anchor:middle;}#mermaid-svg-fSYPfulwMYR9gkVl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fSYPfulwMYR9gkVl .rough-node .label,#mermaid-svg-fSYPfulwMYR9gkVl .node .label,#mermaid-svg-fSYPfulwMYR9gkVl .image-shape .label,#mermaid-svg-fSYPfulwMYR9gkVl .icon-shape .label{text-align:center;}#mermaid-svg-fSYPfulwMYR9gkVl .node.clickable{cursor:pointer;}#mermaid-svg-fSYPfulwMYR9gkVl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fSYPfulwMYR9gkVl .arrowheadPath{fill:#333333;}#mermaid-svg-fSYPfulwMYR9gkVl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fSYPfulwMYR9gkVl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fSYPfulwMYR9gkVl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fSYPfulwMYR9gkVl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fSYPfulwMYR9gkVl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fSYPfulwMYR9gkVl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fSYPfulwMYR9gkVl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fSYPfulwMYR9gkVl .cluster text{fill:#333;}#mermaid-svg-fSYPfulwMYR9gkVl .cluster span{color:#333;}#mermaid-svg-fSYPfulwMYR9gkVl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fSYPfulwMYR9gkVl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fSYPfulwMYR9gkVl rect.text{fill:none;stroke-width:0;}#mermaid-svg-fSYPfulwMYR9gkVl .icon-shape,#mermaid-svg-fSYPfulwMYR9gkVl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fSYPfulwMYR9gkVl .icon-shape p,#mermaid-svg-fSYPfulwMYR9gkVl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fSYPfulwMYR9gkVl .icon-shape .label rect,#mermaid-svg-fSYPfulwMYR9gkVl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fSYPfulwMYR9gkVl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fSYPfulwMYR9gkVl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fSYPfulwMYR9gkVl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 监控告警
✅ 监控告警
QPS/延迟/错误率
✅ 降级方案
Redis挂了降级MySQL
异步处理
✅ 异步统计
MQ+消费者
✅ 定时清理
过期数据
存储层
✅ MySQL分库分表
16库256表
✅ Redis集群
缓存+布隆过滤器
✅ 本地缓存
Caffeine/GoCache
核心组件
✅ 分布式发号器
雪花算法/Leaf
✅ Base62编码工具类
✅ 限流组件
令牌桶/漏桶
部署检查清单:
| 类别 | 检查项 | 状态 | 生活化比喻 |
|---|---|---|---|
| 核心组件 | 分布式发号器(雪花算法/Leaf) | ⬜ | 自动编号机 |
| Base62 编码工具类 | ⬜ | 翻译器 | |
| 限流组件(令牌桶/漏桶) | ⬜ | 餐厅限流 | |
| 存储层 | MySQL 分库分表(16 库 256 表) | ⬜ | 分本花名册 |
| Redis 集群(缓存 + 布隆过滤器) | ⬜ | 快速查询表 + 门禁 | |
| 本地缓存(Caffeine/GoCache) | ⬜ | 手机通讯录 | |
| 异步处理 | 异步统计(MQ + 消费者) | ⬜ | 记账员 |
| 定时清理过期数据 | ⬜ | 清洁工 | |
| 监控告警 | 监控告警(QPS、延迟、错误率) | ⬜ | 保安巡逻 |
| 降级方案(Redis 挂了降级到 MySQL) | ⬜ | 备用方案 |
九、总结(一句话带走)
#mermaid-svg-QNnBbErkIZAuR1am{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QNnBbErkIZAuR1am .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QNnBbErkIZAuR1am .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QNnBbErkIZAuR1am .error-icon{fill:#552222;}#mermaid-svg-QNnBbErkIZAuR1am .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QNnBbErkIZAuR1am .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QNnBbErkIZAuR1am .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QNnBbErkIZAuR1am .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QNnBbErkIZAuR1am .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QNnBbErkIZAuR1am .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QNnBbErkIZAuR1am .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QNnBbErkIZAuR1am .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QNnBbErkIZAuR1am .marker.cross{stroke:#333333;}#mermaid-svg-QNnBbErkIZAuR1am svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QNnBbErkIZAuR1am p{margin:0;}#mermaid-svg-QNnBbErkIZAuR1am .edge{stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .section--1 rect,#mermaid-svg-QNnBbErkIZAuR1am .section--1 path,#mermaid-svg-QNnBbErkIZAuR1am .section--1 circle,#mermaid-svg-QNnBbErkIZAuR1am .section--1 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section--1 text{fill:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth--1{stroke-width:17;}#mermaid-svg-QNnBbErkIZAuR1am .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-0 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-0 path,#mermaid-svg-QNnBbErkIZAuR1am .section-0 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-0 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-QNnBbErkIZAuR1am .section-0 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-0{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-0{stroke-width:14;}#mermaid-svg-QNnBbErkIZAuR1am .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-1 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-1 path,#mermaid-svg-QNnBbErkIZAuR1am .section-1 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-1 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-1 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-1{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-1{stroke-width:11;}#mermaid-svg-QNnBbErkIZAuR1am .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-2 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-2 path,#mermaid-svg-QNnBbErkIZAuR1am .section-2 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-2 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-2 text{fill:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-2{stroke-width:8;}#mermaid-svg-QNnBbErkIZAuR1am .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-3 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-3 path,#mermaid-svg-QNnBbErkIZAuR1am .section-3 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-3 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-3 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-3{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-3{stroke-width:5;}#mermaid-svg-QNnBbErkIZAuR1am .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-4 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-4 path,#mermaid-svg-QNnBbErkIZAuR1am .section-4 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-4 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-4 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-4{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-4{stroke-width:2;}#mermaid-svg-QNnBbErkIZAuR1am .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-5 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-5 path,#mermaid-svg-QNnBbErkIZAuR1am .section-5 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-5 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-5 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-5{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-5{stroke-width:-1;}#mermaid-svg-QNnBbErkIZAuR1am .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-6 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-6 path,#mermaid-svg-QNnBbErkIZAuR1am .section-6 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-6 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-6 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-6{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-6{stroke-width:-4;}#mermaid-svg-QNnBbErkIZAuR1am .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-7 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-7 path,#mermaid-svg-QNnBbErkIZAuR1am .section-7 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-7 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-7 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-7{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-7{stroke-width:-7;}#mermaid-svg-QNnBbErkIZAuR1am .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-8 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-8 path,#mermaid-svg-QNnBbErkIZAuR1am .section-8 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-8 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-8 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-8{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-8{stroke-width:-10;}#mermaid-svg-QNnBbErkIZAuR1am .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-9 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-9 path,#mermaid-svg-QNnBbErkIZAuR1am .section-9 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-9 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-9 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-9{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-9{stroke-width:-13;}#mermaid-svg-QNnBbErkIZAuR1am .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-10 rect,#mermaid-svg-QNnBbErkIZAuR1am .section-10 path,#mermaid-svg-QNnBbErkIZAuR1am .section-10 circle,#mermaid-svg-QNnBbErkIZAuR1am .section-10 polygon,#mermaid-svg-QNnBbErkIZAuR1am .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-10 text{fill:black;}#mermaid-svg-QNnBbErkIZAuR1am .node-icon-10{font-size:40px;color:black;}#mermaid-svg-QNnBbErkIZAuR1am .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .edge-depth-10{stroke-width:-16;}#mermaid-svg-QNnBbErkIZAuR1am .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-QNnBbErkIZAuR1am .disabled,#mermaid-svg-QNnBbErkIZAuR1am .disabled circle,#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:lightgray;}#mermaid-svg-QNnBbErkIZAuR1am .disabled text{fill:#efefef;}#mermaid-svg-QNnBbErkIZAuR1am .section-root rect,#mermaid-svg-QNnBbErkIZAuR1am .section-root path,#mermaid-svg-QNnBbErkIZAuR1am .section-root circle,#mermaid-svg-QNnBbErkIZAuR1am .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-QNnBbErkIZAuR1am .section-root text{fill:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .section-root span{color:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .section-2 span{color:#ffffff;}#mermaid-svg-QNnBbErkIZAuR1am .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-QNnBbErkIZAuR1am .edge{fill:none;}#mermaid-svg-QNnBbErkIZAuR1am .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-QNnBbErkIZAuR1am :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 短链接系统
核心要点
设计原则
读多写少 优化缓存
短码唯一 分布式ID
高并发 多级缓存
技术选型
ID生成: 雪花算法
编码: Base62
缓存: Redis+本地
存储: MySQL分库分表
性能优化
布隆过滤器防穿透
热点数据本地缓存
接口层限流防刷
面试重点
301 vs 302选择
缓存穿透/击穿/雪崩
分库分表策略
容量规划
🎯 一句话总结
短链接系统 = 分布式发号器(保证唯一) + Base62 编码(缩短长度) + 三级缓存(扛高并发) + 302 重定向(方便统计)
🧠 核心记忆点
- 为什么不用 MD5? 有碰撞,像取昵称只取最后一个字,会重名。
- 为什么用 302? 方便统计点击,像邮局每次都来问你"转寄到哪里"。
- 如何扛高并发? 本地缓存(手机通讯录)+ Redis(公司通讯录)+ MySQL(户籍中心)。
- 如何防穿透? 布隆过滤器(门禁系统)+ 空值缓存("查无此人"也记下来)。
参考视频 :内卷的琪某人 - 面试经典:如何设计高并发短链接系统
本文档基于 8 个专家提示词指导改写,遵循深入浅出、生活化比喻、幽默风趣的教学原则。