短链系统设计
短链有哪些优势,系统又该如何设计,类似的文章太多,不重复赘述。
可以参考高性能短链设计, 本文就其中的一些点探讨一下。
一、流程
- 数据量大
-
数据量小
布隆过滤查询是否存在,可改为直接数据库索引查。也可以直接写,看唯一索引是否冲突
二、核心代码示例
这里借用了Guava包封装的MurmurHash方法。
import com.google.common.hash.Hashing;
import java.nio.charset.StandardCharsets;
/**
* 短链设计
*/
public class MurmurHashToBase62 {
private static final String BASE62_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static void main(String[] args) {
// 输入长链接
String longUrl = "https://example.com/some/very/long/url/for/testing";
// 计算 32 位 MurmurHash
int hash32 = Hashing.murmur3_32().hashString(longUrl, StandardCharsets.UTF_8).asInt();
// MurmurHash 32-bit (Decimal): -1888812516
System.out.println("MurmurHash 32-bit (Decimal): " + hash32);
// 转换为正数(避免负值影响进制转换)
long unsignedHash32 = hash32 & 0xFFFFFFFFL;
// 转换为 62 进制
String base62Hash = convertToBase62(unsignedHash32);
// MurmurHash 32-bit (Base62): 2cpym4
System.out.println("MurmurHash 32-bit (Base62): " + base62Hash);
}
// 将数字转换为 62 进制字符串
private static String convertToBase62(long value) {
StringBuilder base62 = new StringBuilder();
while (value > 0) {
int index = (int) (value % 62);
base62.append(BASE62_CHARSET.charAt(index));
value /= 62;
}
// 返回结果(注意:需要反转顺序)
return base62.reverse().toString();
}
}
三、一些关键点
3.1 如何选择多少长度短链
- 6位,可表示568亿个地址
-
4位,可表示1477万个地址
-
如何固定长度( 有利于辨识度 )
// 限制哈希值范围到 62^6 以内 long limit = (long) Math.pow(62, 6); long fixedRangeHash = unsignedHash32 % limit; // 转换为 62 进制 String base62Hash = convertToBase62(fixedRangeHash); // 如果长度不足 6 位,前补零或其他字符 while (base62Hash.length() < 6) { base62Hash = "0" + base62Hash; }因此,如果想采用4位的短链,直接截取转62进制后的前4位即可;如果不够,自行补足
3.2 MurmurHash算法
MurmurHash 是一种非加密型哈希函数,与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。即,冲突概率更低,更适用于于URL这种有着强规律的数据。
-
原理
MurmurHash算法基于混合函数的设计思想,它将输入数据分为若干段,并对每一段执行一个非线性函数(根据数据类型和大小动态调整),将结果合并为一个最终的哈希值。在MurmurHash中,这种分段和混合函数的选择是关键。通过对输入数据进行适当的混合和混淆,MurmurHash能够产生更好的哈希分布,降低碰撞概率。
3.3 如何解决hash冲突
原地址添加自定义参数,然后重新hash
3.4 301 和 302 重定向的区别
- 301,代表 永久重定向,也就是说第一次请求拿到长链接后,下次浏览器再去请求短链的话,不会向短网址服务器请求了,而是直接从浏览器的缓存里拿,这样在 server 层面就无法获取到短网址的点击数了,如果这个链接刚好是某个活动的链接,也就无法分析此活动的效果。所以我们一般不采用 301。
- 302,代表 临时重定向,也就是说每次去请求短链都会去请求短网址服务器(除非响应中用 Cache-Control 或 Expired 暗示浏览器缓存),这样就便于 server 统计点击数
总结: 是采用301还是302,看系统设计对于短链跳转到定位,看性能优先还是数据统计优先。
四、其他方式
方案: 短链前缀+不重复自增ID
- 随机UUID+各类识别码等,不如直接长链hash
- Mysql自增主键,小规模可以玩
- Redis自增
- Snowflake,但是雪花算法生成ID是64位,通过62进制转换,至少是11位;截断的话,增大整体冲突概率
- 利用其他自增ID生成工具,如tinyId等
后话:
如果只是小公司的零散需求,也不考虑统计数据之类的。那么部署一个FTP,用nginx静态代理目录就行了,不需要再去整一堆服务。链接名自己定,反正就那么几个文件。