当前位置: 首页 > article >正文

如何设计一个短链系统?流程如何?

原理

在浏览器输入短链后,请求打到短链服务,短链服务会定位并根据 url 重定向到长链地址,此时浏览器就会跳转网页定位到真正的地址。所以本质原理就是短链服务器根据 url 定位到真正地址,然后通过重定向实现跳转。

后端设计

后端的主要功能是存储短链和长链的对应关系,并且能快速通过短链找到长链。首先需要先生成短链,假设短链的域名是dl.x

  1. 可以通过数据库自增 id 作为短链,往数据库插入一条长链,对应就会得到一个 id

如果用户访问了 dl.x/1 ,解析得到 1,通过主键就能定位到数据库记录,得到长链

这个方式很简单,通过主键查询也很快。如果面试官问这样的方式有什么缺点,你再说: 一旦短链量变多自增 id 会变成很大,比如9999999999999999,这样短链也不短了,而且数字有规律性,容易被人遍历出来。

 2. 哈希算法

可以通过 hash 算法将长链进行 hash 计算,得到固定的长度,比如通过 md5 计算可以得到固定的128bit 数据,还有别的哈希函数,比如 MurMurHash,它既可以生成 128 bit 也可以生成 32bit,不过 32 bit 相比 128 bit 生成速度更慢,目 hash 碰撞的概率更高。

这里再提一下MurMurHash 128bit版本的速度是 md5 的十倍。其次就是crc32,得到的就是 32 位的哈希值,运算速度和 md5 差不多,因此我们可以将长链通过 hash 得到固定的位数,我找了个网上的MurmurHash32例子,我们来看

  • 例如,URL https://example.com/very-long-url-that-needs-to-be-shortened 经过 MurMurHash32 计算后得到 2278507744

  • 最终的短链为 dl.x/2ucnWU

但是这好像比我们平时在短信中看到的短链还长了一些,还能再缩短吗?

当然是可以的,还可以利用进制转化进一步缩短长度!

比如我们取 62 位的,最终的短链就是dl.x/2ucnWU,这样看着是不是感觉就对了? 同理上面的自增 id 也可以通过进制转化进一步缩短。最终的数据库表结构的设计如下:

跳转设计

浏览器具体是如何在输入短链后自动跳到长链地址的就是重定向。

涉及到 HTTP 的知识点,服务器返回 301 或者 302 状态码,然后在 location 上写上长链的地址,浏览器就会自动识别动作,进行跳转。

这两个状态码还是有区别的:

  1. 301 表示永久重定向,即浏览器会默认缓存这次跳转的信息,下次用户在浏览器访问这个短链浏览器不需要请求短链服务,会自动跳转到长链地址。

  2. 302 表示临时重定向,即浏览器不会缓存这次跳转信息,用户每次访问这个短链,都需要请求短链服务得到长链。

  3. 区别就是 301 可以降低短链服务器压力,因为后续用户访问都不需要请求短链后端服务,而 302 则需要每次访问,但是这样一来可以统计短链访问次数,做一些分析。

扩展

如果数据量大了,一张表存储所有短链数据就会有性能问题,因此需要分库分表。

在分库分表的情况下,每个数据库或表的自增 ID 是独立的,这意味着不同数据库或表生成的自增 ID 可能会重复。如果直接使用这些自增 ID 生成短链,会导致短链冲突

  • 因此可以引入全局发号器来实现全局唯一ID 分配,比如唯一ID 可以利用雪花算法生成。然后通过全局 ID 转化的短链数据作为分表的键即可,因为查询肯定是通过短链来查的。

  • 还有哈希方法可能会导致哈希冲突,即不同的长链可能会生成一样的短链,我们可以将 short_url 作为唯一索引,这样就能保证唯一性,如果插入报错,则可以简单在长链后面拼个随机数,重新进行hash,直到生成一个未使用的短链为止,这样就能避免重复了。

  • 还可以引入缓存,比如我们双十一做了一个营销活动,给很多用户推送了短信,此时肯定会有很多用户访问这个短信内的短链,此时我们就可以将短链相关信息放在缓存中,不需要查数据库,利用缓存提高性能。

补充短链场景

一般短链会用在短信场景,因为短信有字数限制,超过一定字数收费不一样,所以太长的连接不合适。

再比如一些社交媒体平台对字数也会有限制。还有一些二维码,如果 url 太长,生成的码也会比较复杂,比较难扫。


http://www.kler.cn/a/591086.html

相关文章:

  • 云原生周刊丨CIO 洞察:Kubernetes 解锁 AI 新纪元
  • TypeScript Symbols 深度解析:在 Vue3 中的高级应用实践
  • Lora微LLAMA模型实战
  • 【Node.js入门笔记8---path 模块】
  • 如何使用 CryptoJS 实现 DES 解密
  • 支持向量机(Support Vector Machine)基础知识2
  • 深度揭秘:蓝耘 Maas 平台如何重塑深度学习格局
  • python二级每日十题(1)
  • SQLMesh 系列教程:Airbnb数据分析项目实战
  • ubuntu中的ens33网卡在ifconfig中被默认关闭了?
  • Netty基础—8.Netty实现私有协议栈一
  • 华为海思 CPU「麒麟 X90」曝光
  • 谱分析方法
  • CPP从入门到入土之类和对象Ⅰ
  • Leetcode 3483. Unique 3-Digit Even Numbers
  • MySQL 锁
  • 【GPT-SoVITS】GPT-SoVITSAPI调用:让二次元角色开口说话,打造专属语音合成系统
  • 反向波动策略思路
  • 默认参数 d = {} 的陷阱
  • springboot项目日志不打印