长链转短链生成与访问

最近研究了下长短链的生成与访问,发现这其中有不少的可以仔细研究的点,现在写下这篇文章记录下

短链的生成

首先是长链和短链的定义,以及应用的场景。

我们经常可以看到有些链接很长例如:https://www.google.com.hk/search?q=%E6%B7%98%E5%AE%9D%E6%B4%BB%E5%8A%A8+%E9%95%BF%E9%93%BE&oq=%E6%B7%98%E5%AE%9D%E6%B4%BB%E5%8A%A8+%E9%95%BF%E9%93%BE&aqs=chrome..69i57j33i160l2.9434j0j7&sourceid=chrome&ie=UTF-8

这样的链接如果是在微博这种有字数限制或者短信这种超过一个长度额外收费的服务来说就很不友好,短链的优势在这里就很明显,例如刚才的长串如果是https://www.google.com.hk/jhd351dfs,
那么这个问题就被轻松解决了。还有另一个应用场景, 在一个销售业务部门可能会根据每个不同的销售分享不同的链接来对不同的销售绩效进行考核,或者类似的是用户点击别人分享的链接,分享者有收益。这种场景有一种处理方案就是在链接上拼接分享人的信息,点击之后再解析这个参数,那么用短链来隐藏这个信息就很重要。

理解这个应用场景其实我们大致也能知道所谓的短链其实就是将原先的长链进行处理,点击短链访问的时候本质上还是在访问长链。也就是我们的短链服务其实是一个中转映射,现将长链按照我们设定好的转成一个新的地址,
当用户访问这个短链的时候其实是先访问了短链的服务,短链服务要先根据之前的规则重定向到原来的长链地址

那我们先来看下这个生成短链的方式

目前查阅网上的资料来看核心的思路都是先将长链分配一个在我们的系统中唯一的序号,将这个序号转成一个62进制的数直接作为短链的地址,我们这边保存两者的映射关系,当用户访问短链时根据请求的数值查出对应的长链在进行重定向即可。
ok,现在我们开始思考一下下面几个问题

  1. 这个唯一的序号我们要怎么生成
  2. 一个地址多次请求怎样确保返回的地址相同
  3. 为什么返回的是62进制

唯一id的生成方法

首先我们看下第一个唯一的序列要怎么生成,其实说白了本质就是生成一个唯一的id,那么这样的方法就比较多了,我们一般可以采用下面几种方式进行生成

  •  UUID
  • snowflakes 即雪花算法
  • redis
  • MySQL自增主键
  • zookeeper 生成唯一id

by the way我们来聊聊这几种方式的优缺点,这其实也是面试一个经常碰到的点

数据库自增id

数据库方式是一种简单的方式,就是依赖数据库的自增长主键来实现。但是强依赖数据库在性能方面会收到影响,同时要考虑到分布式部署的一致性以及单点故障的问题

redis

redis生成唯一id是依赖redis的原子性操作,相对于数据库在性能上有比较大的优势,但是要引入新的组件,同时如果redis发生故障会对这个服务有影响

UUID

首先UUID生成随机数的方案是生成的效率高,本地生成没有网络消耗,但是他的缺点
1. 生成的uuid相对来说比较长
2. 不同的版本会有不一样的问题,如使用mac地址来生成会导致mac地址泄露、使用随机数会有重复情况等

snowflakes算法

snowflakes算法是推特的研发的一种随机数实现,生成一个long类型的随机数,用64bit不同的位来表示时间戳、机器位。雪花算法生成的唯一id,可以保证全局唯一同时满足生成id递增,在高并发情况下也有不错的表现。
但是由于依赖时间戳会出现时间回溯的问题,也就是当一台机器上时间向历史时间修正会出现重复的id,对于这种情况一般有下面解决方式
1. 直接抛出异常
2. 如果时间回溯过小,可以等待
3. 采用之前的最大时间后的时间

ZooKeeper

ZooKeeper生成唯一id是利用zk的znode数据版本来生成序列号可以生成 32 位和 64 位的数据版本号。可以利用这个版本号来作为唯一id。由于依赖zk,并且是多次调用需要在并发较大的时候使用分布式锁,拿在高并发中性能十分有影响

如何保证一个地址多次请求返回的地址相同

第二个问题是我们如何保证一个地址多次请求返回的地址相同
对于这个问题就很简单了,我们只需要将原先的url和之前生成的映射保存下来,每次申请之前先进行一次查询即可,但是这里的问题是如何提高效率。使用缓存是最优解,直接将映射关系放入到redis中,
但是这种方案需要考虑到如果redis中数据丢失那么如果有已经申请的重复请求会出现不一致的情况,如果直接使用MySQL查询就会出现性能问题。对于这个其实就是一种业务取舍的问题。如果是公司内部的系统需要确保请求的短链必须一致那么可以直接使用MySQL查询。
如果是那种对外的可以考虑直接使用Redis作为缓存,如果丢失了就重新生成。对于第一种查询MySQL的方案还有一种优化方案就是在查询MySQL之前增加一个布隆过滤器(小心布隆过滤器存在误报)

为什么返回的62进制数

我们一般使用0-9、a-z、A-Z总共62个字符,如果使用6位的短链可以生成 62 ^ 6 - 1 =56800235583。对于这个问题还有一点要注意的是我们处理成62进制的数据是现将一个10进制的数转成62进制。如果是雪花算法生成的long数据可以直接计算,
但如果是UUID生成的字符串则需要先进行转换,一般这种方式使用的是计算hash值的方式

短链的访问

最后我们聊一下如何将短链还原成长链。最简单的当然是根据请求的短链在我们数据库中查询到对应的短链,进行重定向。这里有两个点我们要注意下:

  1. 我们用怎么样的请求去接收短链,我们的请求肯定不会带上多层目录,一般返回如s.atlantis.com/d15fd12s,而不是s.atlantis.com/short/d15fd12s。我们的controller可能会一般拦截所有的请求
  2. 在找到对应的长链之后的重定向我们设置的http code是301还是302(重点分析,面试可以好好聊聊)

接受识别短链的请求

  • 拦截器

第一个就是在代码中使用拦截器,在拦截器中根据请求的域名是否是设置的短链域名来调用指定的方法,但是这里要注意这个拦截器会拦截所有的请求,会严重影响性能

  • Nginx

第二个方案是在nginx中进行配置,将我们的服务单独进行部署作为短链的专用服务,使用不同的端口进行区分。在我们的Nginx中进行配置,匹配短链请求的域名全部发送到指定的端口的短链服务

重定向中http状态码的设置

在我们的短链进行重定向的时候设置的http状态码是301还是302,首先我们要知道301和302的区别,这两个都是进行重定向,301表示资源永久转移,后续浏览器就不会再请求我们的短链服务,直接访问长链的地址。
很明显这样对于我们的短链服务压力会比较小。如果是设置成302的话,就是资源的临时重定向。浏览器的后续请求会再次请求我们的短链服务而不是缓存长链的地址进行请求。
对于这两种方案的优劣性来分析可知301对短链的访问压力比较小,302对短链的访问压力大,但是我们可以借由这个特性来获取对于链接的请求次数这样的数据。这种的话对于内部系统进行数据分析是非常有用的。所以这里重定向的http状态码可以根据实际的业务来决定。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值