设计百万QPS的短链服务

1、什么是短链接和长链接

上图是我们经常可以收到的一条流量通知的短信,短信有一个链接A:

https://dx.100XX.cn/JG1mEA

这个就是短链接;当我们点击短链接A之后就会自动的跳转到链接B

https://wap.zj.100XX.cn/szhy/2022/openMiniProgram/index.html?id=8ace47a58414b7d201843b8842ed15bb

这个就是真实的访问链接,此链接我们称为长链接。

为什么需要短链接?

(1)短链通常较短,字符数量少,更加节省字数;

(2)各种平台发文有字数限制;

(3)节约成本,如短信发送时短链接就不需要拆成多条文本发送;

(4)占用空间少

长链接和短链接跳转的原理

状态码301和302的区别:

(1)状态码301
301 是永久重定向。301 跳转会默认被浏览器缓存,当用户第一次访问某个短链后,如果服务器返回 301 状态码,则这个用户在后后续多次访问同一短链接地址,浏览器会直接请求缓存中的跳转地址,不会再请求短链服务重新获取地址。这么做的优点是降低了服务器的压力,但是无法统计短链接的点击次数。

(1)状态码302
302是临时重定向。302 跳转默认不会被浏览器缓存,除非提示浏览器缓存。因此用户每次访问同一短链地址,浏览器都会去duan链服务器上重新取长链接的地址。此方式优点是能够统计到短链接被点击的次数,但是服务器的压力变大了。

2、实现短链接和长链接的映射

(1)哈希法

哈希法推荐 Google 出品的 MurmurHash 算法,MurmurHash 是一种非加密型哈希函数,非加密性能较高。将长链接通过哈希算法映射成一个短值如下:

数据存放到数据库(如Mysql)如下:

当前请求短链服务器的时候(https://www.longxia/v/short?id=longxia

通过id=longxia到数据匹配到长链接,然后将长链接返回。

哈希法的会存在哈希冲突的问题(即就是两个不同的URL可能会生成相同的短链接),为了解决这个问题我可以采用增加salt字段,方案如下:

将短链字段设置为唯一键,重复短链插入数据库抛出异常时候进行处理: 增加盐值到长链后面,然后重新使用这个拼接的长链进行hah计算。此方式最多重试三次,尽最大努力解决哈希冲突问题。访问短链时,一并取出salt值,将长链处理后进行返回。

(2)id映射方案

可以使用Mysql的自增主键值来映射长链接

数据库中存储的方式

当访问短链接(https://www.longxia/v/short/1)可以通过这个短链后面的1来定位到长链,然后返回给服务消费方

数据库自增id映射方案的缺点:

(1)id太规律了,容易被攻击;

(2)id自增到一定程度后,数字还是很长;

由于主键id直接暴露存在一定的问题,所以使用redis、uuid、雪花算法等替换方案。

(2)redis方案

在Redis中创建一个键,使用INCR命令递增该键的值,并将递增后的值作为唯一ID返回。由于Redis的INCR命令是原子性操作,所以可以确保每次生成的ID都是唯一的。为了增加ID的安全性,一般不建议使用Redis自增的数值,而是拼接一些其它信息,方案如下:

(3)uuid方案

UUID是通过一系列算法生成的128位数字,通常基于时间戳、计算机硬件标识符、随机数等元素; uuid 方案实现简单,无需网络交互就能保证了ID的唯一性。

UUID.randomUUID().toString()

(4)雪花算法方案

雪花算法生成一个64位的大小的整数,结构如下:

雪花算法的生效id的效率高,但是雪花算法要避免时钟回拨的问题(会出现id重复的问题)

3、设计短链服务

由于是访问量很大,所以我们在设计的时候采用了LVS+Nginx扛住第一层的大流量。

(1)LVS使用keepalived来保证高可用,LVS是工作在第四层并且其负载能力强,它负责将请求分发到nginx上;

(2)nginx单机的并发5万,针对百万的并发至少需要20台nginx来处理大的流量,nginx将请求转发到公司的网关上。

(3)网关根据服务的URL来解析地址找到对应的服务器,由于是百万流量所以网关也需要做集群来处理请求。

(4)网关将请求转发到真实的短链服务上,短链服务自身使用了sentinel来限流、使用本地缓存(常见的是Guava、 caffeine )、分布式缓存(如redis)来缓存数据,使用布隆过滤器过滤无效的请求。

(5)有效的请求未命中缓存,此时就查询数据库,由于数据库抗并发能力弱,所以对数据库做了主从模式、读写分离方式来应对高并发

(6)数据库中查询出来的数据要同步到缓存中,以便于下次同样的短链请求可以不查询数据库而直接给消费者提供数据响应。

7