腾讯女后端设计的高并发短链系统方案让面试官当场发offer
短链系统由域名与全局唯一随机码组成,通过302重定向实现跳转。随机码生成可采用Base62编码、Hash算法压缩或全局唯一ID转换。冲突检测依赖数据库唯一索引或布隆过滤器,冲突时拼接随机字符串重新Hash。高并发场景需支持水平扩展、服务限流及监控预警。
业务量小的公司,按成本搭个单机或者几台服务器做负载也就够了。但业务量一旦上来,高并发就是绕不开的课题——怎么保证稳定性?怎么支持水平扩展?出了问题有没有一套完善的监控和预警?这些都得提前想好。
比如下面这种客服评价信息,相信大家都不陌生。点击信息里的“蓝色字体”,就会跳转到一个具体的网页。
其实,这串蓝色字符有个很专业的名字:短链。它可以是 URL 地址,也可以是一个二维码。而整个跳转流程的背后,是一套完整的短链系统。今天我们就来拆解一下:怎么设计一套高性能的短链系统。
为什么需要短链?
存在即合理,这事儿得从三个角度来说。
1. 相对安全
短链不容易暴露访问参数,生成方式可以完全迎合信息平台的规则,能有效规避关键词、域名屏蔽等风险。而原始 URL 很可能因为包含特殊字符被信息系统误判,导致链接无法跳转。
2. 美观
精简的文字更符合美学观念,让人不那么反感。
3. 平台限制
信息发送平台有字数限制。在整条信息字数不变的前提下,把链接缩短,其他部分的文字描述就能增加,这更有利于达到信息的实际目的(比如营销)。
短链的组成
如下图,短链通常由两部分组成:域名 + 随机码
图片
短链的域名最好和其他业务域名分开,而且要尽量简短,甚至可以不带有业务含义(比如 xyz.com)。因为短链大多用于营销,可能被第三方平台屏蔽。随机码则需要全局唯一,建议控制在 10 位以下。
短链的跳转原理
先看一个简单的跳转例子。下面这段代码演示了一个 302 重定向:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.view.RedirectView;
@Controller
public class RedirectController {
@GetMapping("/{shortCode}")
public RedirectView redirect(@PathVariable String shortCode) {
String destUrl = "https://yuanja va.com";
// destUrl = getDestUrlByShortCode(shortCode); // 真实的业务逻辑
return new RedirectView(destUrl);
}
}
在浏览器访问短链 http://127.0.0.1:8080/s2TYdWd 后,请求会被重定向到 https://yuanja va.com。下图为浏览器控制台信息:
图片
可以看到 302 状态码,请求被 Location 到了另一个 URL。整个交互流程如下图:
图片
是不是有点偷梁换柱的感觉?
总结一下短链跳转的核心思想:
- 生成随机码,将随机码和目标 URL(长链)的映射关系存入数据库;
- 用域名+随机码生成短链,推送给目标用户;
- 用户点击短链后,请求到达短链系统,系统根据随机码查找出对应的目标 URL,然后将请求 302 重定向到目标 URL(长链)。
关于重定向,有 301 和 302 两种选择,怎么选?
- 302 临时重定向:每次请求短链都会先到达短链系统,然后重定向到目标长链。这样方便做点击数等统计。通常采用 302。
- 301 永久重定向:第一次请求拿到目标长链后,浏览器会缓存,后续请求直接跳转到缓存的长链,不再经过短链系统。这样只能统计到第一次访问的数据,一般不采用 301。
如何生成短链?
从短链的组成可知:短链 = 域名 + 随机码。那么问题就变成了如何生成一个全局唯一的随机码。业内通常有三种做法:
1. Base62
Base62 表示法是一种基数为 62 的数制系统,包含 26 个大写字母、26 个小写字母和 10 个数字,共 62 个字符。代码如下:
import ja va.security.SecureRandom;
public class RandomCodeGenerator {
private static final String CHAR_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final SecureRandom random = new SecureRandom();
public static String generateRandomCode(int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int rndCharAt = random.nextInt(CHAR_62.length());
char rndChar = CHAR_62.charAt(rndCharAt);
sb.append(rndChar);
}
return sb.toString();
}
}
如果是 6 位随机数,有 62⁶ - 1 ≈ 568 亿种组合;7 位则有 62⁷ - 1 ≈ 3.5 万亿种,完全够用。
2. Hash 算法
Hash 算法是最容易想到的办法,比如 MD5、SHA-1、SHA-256、MurmurHash。但这类算法生成的 Hash 值通常较长,常见做法是把 Hash 值进行 62/64 进制压缩。
下面这段代码用 Google 的 MurmurHash 算法,将长链 Hash 成一个 32 位的十进制正数,再转换成 62 进制,得到一个 6 位的随机数:
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import ja va.nio.charset.StandardCharsets;
public class MurmurHashToBase62 {
private static final String BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String toBase62(int value) {
StringBuilder sb = new StringBuilder();
while (value > 0) {
sb.insert(0, BASE62.charAt(value % 62));
value /= 62;
}
return sb.toString();
}
public static void main(String[] args) {
String input = "https://yuanja va.cn/posts/short-link-system/design?code=xsd&page=1";
HashFunction hashFunction = Hashing.murmur3_32();
int hash = hashFunction.hashString(input, StandardCharsets.UTF_8).asInt();
if (hash < 0) {
hash = hash & 0x7fffffff; // 通过丢弃符号位转为正数
}
String base62Hash = toBase62(hash);
System.out.println("base62Hash:" + base62Hash);
}
}
3. 全局唯一 ID
很多大中型公司都有自己的全局唯一 ID 生成服务,可以直接使用这些 ID,或者用雪花算法生成全局唯一 ID,再经过 62/64 进制压缩。
如何解决冲突?
前两种方法(Base62 和 Hash 算法)本质上都是哈希函数,虽然冲突概率已经很低,但万一冲突了怎么办?解决冲突,首先得检测到它。通常有两种检测方案。
数据库锁
以 MySQL 为例,表结构如下:
CREATE TABLE `short_url_map` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`long_url` varchar(160) DEFAULT NULL COMMENT '长链',
`short_url` varchar(10) DEFAULT NULL COMMENT '短链',
`gmt_create` int(11) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE INDEX `short_url` (`short_url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
给 short_url 加上唯一索引,插入时如果发生 Hash 冲突(short_url 值重复),数据库会抛错导致插入失败。在业务代码里捕获这个错误就能检测出冲突。当然,也可以先用 short_url 查询,如果查到数据,说明冲突了。
这种依赖数据库的检测方式,对数据库是个额外开销。如果流量较大,需要保证数据库的性能。
布隆过滤器
在 DB 操作上游加一个布隆过滤器。长链生成短链后,先用短链在布隆过滤器中查找:如果存在说明冲突,如果不存在则说明 DB 里没有这条短链,可以插入。单机可以用 Google 的布隆过滤器,分布式环境可以用 RedisBloom。
整体流程可以抽象成下图:

检测出冲突后怎么解决?很简单——再 Hash。在长链后面拼接一个 UUID 之类的随机字符串,然后重新 Hash,用新值再做一次检测。这样一来,冲突概率又被大大降低了。
高并发场景的架构
流量不大的时候,上面那些方法怎么折腾都合理。但架构要想扛得住高并发、大流量,就得支持水平扩展。比如:
- 采用微服务功能模块分离,比如短链生成服务和长链查询服务分开;
- 功能模块需要支持水平扩容,能动态增加节点;
- 缓解数据库压力,比如分区、分库分表、主从、读写分离;
- 服务的限流和自保机制;
- 完善的监控和预警机制。
这里给出一套比较完整的设计思路图:
图片
总结
从一条客服评价信息切入,我们分析了短链的构成、跳转原理,给出了业内常用的实现算法,也聊了架构上的建议。业务量小的公司,按成本搭服务就行;业务量大的公司,重点考虑高并发场景下的稳定性、水平扩展和监控预警。说到底,很多系统都是在一次次业务流量的挑战下成长起来的。我们不断打磨自己——宏观看架构,微观看代码——自然也就跟着业务和系统一起成长了。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
台式机加装固态硬盘怎么选?三星9100 PRO深度解析
台式机升级存储常受限于系统启动慢、游戏加载卡顿与大文件传输延迟。本文基于三星9100 PRO的PCIe 5 0架构、14800MB s读取、13400MB s写入、2200K 2600K IOPS、1TB~8TB容量、第八代V-NAND与5nm主控、镍涂层散热与DTG技术、散热片版适配及魔术师软件,提供选购判断与安装兼容性要点,帮助读者评估是否值得一步到位升级。
宁德时代2026年中期分红61.8亿元,同比增35%,创历史新高
宁德时代发布2026年中期分红方案,总额达61 8亿元,同比增长35%。本文梳理分红具体安排、历史对比、业绩支撑及分红机制,帮助投资者评估公司现金流实力与股东回报策略。
企业硬盘报废销毁合规指南:如何选择专业机构与处理流程
企业硬盘报废面临数据复原与合规风险,需选择具备资质且流程透明的专业机构。本文解析行业乱象,介绍以团体标准为核心的合规销毁流程,涵盖上门收运、消磁粉碎、视频溯源及尾料处置,帮助企业规避泄密责任,确保数据安全闭环。
机密文件销毁找什么机构?认准团标参编与资质合规
机密文件销毁找什么机构?核心在于甄别服务商是否具备正规保密资质及是否参与行业标准制定。本文解析《商业秘密及敏感信息载体销毁通用规范》团标要求,提供筛选销毁机构的实操指南,帮助企业规避数据泄露风险,确保销毁流程合规可溯。
影石Insta360 X6全球首销登顶:8K全景画质与AI创作功能解析
影石Insta360 X6全球同步发售即登顶国内外主流平台销量榜首。本文解析其搭载的索尼定制方形大底传感器、4nm AI三芯架构及8K50fps画质,详解3D时光舱、AI导演等独家功能,探讨全景相机从专业工具向大众智能创作设备的演进趋势。
- 热门数据榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2026-09-01 11:26
2026-09-01 06:41
2026-08-31 11:19
2026-08-31 11:19
2026-08-31 11:18
2026-08-31 11:18
2026-08-31 11:17
2026-08-31 11:17
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

