短链接生成(鹅场面试官:短链接系统的原理是什么?怎么实现的?)

引言

相信你在生活中会收到很多短信,尤其是在最近的双十一活动期间,而那些短信有两个特点。第一个是几乎都是垃圾短信,这里可以忽略。第二个是链接很短,比如下面这个:



我们知道,有些短信是有字数限制的,直接放一个带各种参数的链接是不合适的。还有一点就是我们不想暴露参数。好处如下:

  • 太长的链接很容易被限制长度。
  • 短链接看起来简洁,长链接看起来愚蠢。
  • 安全,不想公开参数。
  • 链接转换可以统一,当然也可以实现统计点击等操作。
  • 这背后的原理是什么?怎么发生的?你会如何设计这样一个系统?[来自鹅场采访者]

    短链接的原理短链接展示的逻辑

    这里最重要的知识点是重定向。我们先来回顾一下http的状态码:

    分类

    意义

    1**

    服务器接收请求,并需要请求者继续操作。

    2**

    成功,操作被成功接收和处理。

    短链接在线生成

    3**

    重定向,需要进一步操作来完成请求。

    4**

    客户端错误,请求包含语法错误或请求无法完成。

    5**

    服务器错误,服务器在处理请求时遇到错误。

    那么从3开始的状态代码都是关于重定向的:

  • 00:多选,可以存在于多个位置。
  • 31:永久重定向,浏览器会缓存并自动重定向到新地址。
  • 02:临时重定向,客户端将继续使用旧的URL。
  • 303:查其他地址,类似301。
  • 04:未修改。请求的资源尚未修改。当服务器返回此状态代码时,不会返回任何资源。
  • 05:访问资源需要代理。
  • 36:废弃状态代码
  • 07:临时重定向,使用Get请求重定向
  • 整个跳跃过程:

  • 1.用户访问短链接并请求到达服务器。
  • 2.服务器用长链接替换短链接,然后将重定向的状态代码301/302返回给浏览器。
  • 301永久重定向会导致浏览器缓存重定向地址,短链接系统不会正确统计访问次数。
  • 02临时重定向可以解决次数不准确的问题,但是每次改成短链接系统,服务器的压力就会增加。
  • 3.浏览器得到重定向的状态码和真正需要访问的地址,重定向到真正的长链接。
  • 从下图可以看出,链接确实被302重定向到新地址,返回的头中有一个字段:Location是要重定向的地址:



    短链接怎么设计的?全局发号器

    当然,我们首先想到的是压缩。和文件压缩一样,压缩后我们解压还原到原链接,重定向到原链接。不幸的是,这是行不通的。你见过有什么压缩方法可以直接把这么长的数字压缩到这么短的长度?其实是不可能的。就像Huffman树一样,只能高效压缩重复字符多的字符串。像link可能需要很多参数,存在各种不规则性,直接压缩算法不现实。

    https://dx.10086.cn/tzHLFw和https://gd.10086.cn/gmccapp/web page/pay phone money/index . html怎么样?channel=之间的交换是什么?前面的路径不变,变的是后面的路径,也就是tzHLFw和gmccapp/web page/payphonemoney/index . html?通道=之间的转换。

    其实也很简单,就是数据库中的一段数据,一个id对应一个长链接(相当于一个全局发送者,一个全局唯一的ID):

    编号

    全球资源定位器(Uniform Resource Locator)

    一个

    https://GD . 10086 . cn/gmccapp/网页/payPhonemoney/index.html?渠道=

    这里用的是我们之前讲过的分布式全局唯一id。如果我们直接用ID作为参数,似乎是可以的:https://dx.10086.cn/1,在访问这个链接的时候,去数据库查询真实的网址,然后重定向。

    单机的唯一ID很简单,AtomicLong可以用,分布式的不行。简单来说,可以用redis,或者自己增加数据库,或者可以考虑Zookeeper之类的。

    id 转换策略

    但是直接使用递增的数字有两个缺点:

  • 数量很大的时候,还是很长的。
  • 增量数,不安全,太规律。
  • 很明显,我们平时看到的链接不是数字,一般都是大小写字母加数字。为了缩短链接的长度,我们必须转换id。比如我们的短链接由a-z,A-Z,0-9组成,相当于62位,把id转换成62位:

    public class short URL { private static final String BASE = & # 34;0123456789 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz & # 34;; public static String to base 62(long num){ StringBuilder result = new StringBuilder(); do { int I =(int)(num % 62); result . append(base . charat(I)); num/= 62; } while(num & gt;0); return result.reverse()。toString(); } public static long to base 10(String str){ long result = 0; for(int I = 0;我& ltstr . length();i++){ result = result * 62+base . index of(str . charat(I)); } 返回结果; } public static void main(String[]args){ //tzHLFw system . out . println(to base 10(& # 34;tzHLFw & # 34)); system . out . println(to base 62(27095455234 l)); } } id转62位key或key转id已经实现,但是计算还是比较耗时,不如加一个字段保存,这样数据库就变成了:

    编号

    全球资源定位器(Uniform Resource Locator)

    27095455234

    tzHLFw

    https://GD . 10086 . cn/gmccapp/网页/payPhonemoney/index.html?渠道=

    但是,仍然很容易猜测id和密钥之间的对应关系。如果通过遍历访问,还是很不安全的。如果担心,可以随机打乱短链接的字符顺序,或者在适当的位置添加一些随机生成的字符,比如第一、四、五位是随机字符,其他位置不变。只要我们在计算时将对应关系保存到数据库中,就可以通过连接的键找到对应的url。(值得注意的是,密钥必须是全局唯一的,如果有冲突,必须重新生成)

    一般短链接都有过期时间,所以我们还必须在数据库中添加相应的字段。在访问的时候,首先要判断它们是否过期,如果过期了,我们就不重定向了。



    性能考虑

    如果暴露了大量的短链接,数据库中有大量的数据,此时可以考虑使用缓存优化。生成的时候顺便把缓存写进去,然后读取的时候直接去缓存就行了,因为短链接和长链接的关系不会被修改,即使修改也是很低的频率。

    系统的id用完了怎么办?这个概率很小。如果真的发生了,已经过期的旧身份证号可以重新使用。

    如果有人疯狂要求一些不存在的短链接怎么办?其实这就是缓存渗透。缓存渗透意味着大量请求缓存和数据库中不可用的数据。例如,订单号不能为-1,但是用户请求订单号为-1的大量数据。因为数据不存在,所以数据不会存在于缓存中,所有请求都会直接穿透到数据库中。如果被恶意用户利用疯狂地请求不存在的数据,会导致数据库压力过大甚至崩溃。

    针对这种情况,我们一般可以使用Bloom filter过滤掉不存在的数据请求,但是我们这里的id是内在递增有序的。其实我们的音域一般都是知道的,比较好判断。超出的部分肯定是不存在的,或者说请求到达时,在缓存中放一个空对象是没有问题的。

    链接:面试官说:你可以设计一个短链接生成系统——第十六章——博客公园(cnblogs.com)

    您可以还会对下面的文章感兴趣

    使用微信扫描二维码后

    点击右上角发送给好友