关于面试:答面试官问如何设计短url服务

什么是短url

短url, 顾名思义,就是将长网址缩短到一个很短的网址,用户拜访这个短网址能够重定向到本来的长网址(还原)。这样能够达到易于记忆、转换的目标,还有暗藏链接参数,利于短信推广的作用,罕用于有字数限度的短信、微博、二维码等场景。

谬误答案

这个实现的思路真的是天花乱坠,此处总结几种谬误的实现形式来避坑。

1. 实现一个算法,能够间接把一百个字符左右的长网址缩短到10位以内,并能够原样还原,即可逆

不可能的。为所有可能存在的长链接实现一一对应,自身是不可能的,会呈现碰撞,多个长链接对应一个短链接,所以不会可逆。

2. 实现算法将长地址转短地址,不实现逆运算,将短长对应关系存数据库中

不可能的。没有扭转实质(长链接数量远多于长链接),只有长链接够多,必然会碰撞

3. 用一个hash算法,生成的短链接碰撞后,在短链接前面加1,2,3

物理逻辑上可行,生产利用不可行。效率会不可控的升高,通过算法算进去短url之后,hash碰撞后生成多个xx1,xx2,xx3….xx20…的短url,长短对应数量不可控,查找效率会升高。

4. 随机生成一个短地址,去数据库查找是否用过,用过就再随机,直到随机到一个没用过的短地址,存数据库

物理逻辑上可行,生产利用不可行。每次生成都有必要的全量查问操作,必定是不OK的。

5. 保护一个超级大的全量数据,事后生成超过理论生产应用的短url,接口调用间接颁发,同步批改短url应用状态。

物理逻辑上可行,生产利用低可用。具体是在redis还是db里批量生成其实是截然不同的两种实现。

若是redis, 那么外面要放入全量的短url么?否则怎么晓得这个短url到底是不是惟一的?如果全量,那对redis的可用性就要严格保障,为了高可用,就须要多节点同步维持全量数据,这个过程要做好不是那么的容易; 若是db, 那么就要有大量的并发锁定,意味着大量读写,这个对数据库也是个考验。

正确答案

建设一个发号器,每次有一个新的长URL进来,咱们就减少一,并且将新的数值返回.第一个来的url返回”www.x.cn/0″,第二个返回”www.x.cn/1″.

细节问题

短url的还原跳转用301还是302?

301是永恒重定向,302是长期重定向。

短地址一经生成就不会变动,所以用301是合乎http语义的。同时浏览器会对301申请保留一个比拟长期的缓存,这样就加重对服务器的压力;而且301对于网址的SEO有肯定的晋升。然而很多状况下咱们须要对接口点击或者用户行为进行一些业务监控解决的时候,301显著就不适合了(浏览器间接依照缓存数据跳转了), 所以很多业务场景下还是采纳302比拟适合。

字符超长问题

即便到了10亿(Billion)转换而成的62进制也无非是6位字符,所以长度根本不在思考范畴内,这个范畴足够应用了。

对应关系如何存储?

这个对应数据必定是要落盘的,不能每次零碎重启就从新排号,所以能够采纳mysql等数据库来存储.而且如果数据量小且qps低,间接应用数据库的自增主键就能够实现.

如何保障长短链接一一对应?

依照下面的发号器策略,是不能保障长短链接的一一对应的,你间断用同一个URL申请两次,后果值都是不一样的.

为了实现长短链接一一对应,咱们须要付出很大的空间代价,尤其是为了疾速响应,咱们能够须要在内存中做一层缓存,这样子太节约了.

然而能够实现一些变种的,来实现局部的一一对应, 比方将最近/最热门的对应关系存储在K-V数据库中,这样子能够节俭空间的同时,放慢响应速度.

短URL的存储

咱们返回的短URL个别是将数字转换成62进制,这样子能够更加无效的缩短URL长度,那么62进制的数字对计算机来说只是字符串,怎么存储呢?间接存储字符串对等值查找好找,对范畴查找等太不敌对了.

其实能够间接存储10进制的数字,这样不仅占用空间少,对查找的反对较好,同时还能够更加不便的转换到更多/更少的进制来进一步缩短URL.

短码平安问题

依照算法从0-61都是1位字符,而后2位、3位…这样的话很容易被人发现法则并进行攻打,当然进攻伎俩很多,申请签名之类的平安验证伎俩不在本文探讨范畴内。

首先计数器能够从一个比拟大的随机两头值开始,比方从10000开始计数,他的62进制是 2Bi 3位的字符串;

而后采纳一些校验位算法(比方Luhn改良一下),计算出1位校验位拼接起来,4位短码,这样能够排除肯定的平安危险;

再加点平安料的话,能够在62进制的转换过程中把排序好的62个字母数字随机打乱,比方ABCD1234打乱成1BC43A2D, 转换的62进制也就更难hack了;

最初如果仍不释怀,还能够在某些地位(比方1,3,5)插入随机数,让人无奈看出法则来也能够达到良好的成果。

同一长网址短url是否应该雷同问题

发号策略中,是不判断长地址是否已转过,所以造成后果就是一长对多短,有人说节约空间,建设一个长对短的map存储即可,然而用map存储自身就是节约大量空间,甚至是用大空间换小空间,这就要思考是否真有必要做一一对应,不能一对多;

最简略计划:建一个长对短的map,空间换空间,

更好的计划:用map存储”最近”生成的长对短关系,一小时过期机制实现LRU淘汰

长对短流程:

  1. 这个“最近”表中查看一下,看长地址有没有对应的短地址
  2. 有就间接返回,并且将这个key-value对的过期工夫重置为一小时
  3. 如果没有,就通过发号器生成一个短地址,并且将这个“最近”表中,过期工夫为1小时

一个地址被频繁应用,那么它会始终在这个key-value表中,总能返回当初生成那个短地址,不会呈现反复的问题。如果它应用并不频繁,那么长对短的key会过期,LRU机制主动就会淘汰掉它。

这样在空间和发号数量之间获得了一个均衡,此处也应该看具体的业务需要来,是否会存在一对多的状况。比方下单未领取,给用户发短信召回,短信内的短url外面存在用户昵称,订单号等个性化信息,即不须要减少这一逻辑环节了。

高并发

如果间接存储在MySQL中,当并发申请增大,对数据库的压力太大,可能会造成瓶颈,这时候是能够有一些优化的.

缓存

下面保障长短链接一一对应中也提到过缓存,这里咱们是为了放慢程序处理速度.

能够将热门的长链接(须要对长链接进来的次数进行计数),最近的长链接(能够应用redis保留最近一个小时的)等等进行一个缓存,保留在内存中或者相似redis的内存数据库中,如果申请的长URL命中了缓存,那么间接获取对应的短URL进行返回,不须要再进行生成操作.

批量发号

每一次发号都须要拜访一次MySQL来获取以后的最大号码,并且在获取之后更新最大号码,这个压力是比拟大的.

咱们能够每次从数据库获取10000个号码,而后在内存中进行发放,当残余的号码有余1000时,从新向MySQL申请下10000个号码.在上一批号码发放完了之后,批量进行写入.

这样能够将对数据库继续的操作移到代码中进行,并且异步进行获取和写入操作,保障服务的继续高并发.

分布式

下面设计的零碎是有单点的,那就是发号器是个单点,容易挂掉.

能够采纳分布式服务,分布式的话,如果每一个发号器进行发号之后都须要同步给其余发号器,那未必也太麻烦了.

换一种思路,能够有两个发号器,一个发单号,一个发双号,发号之后不再是递增1,而是递增2.

类比可得,咱们能够用1000个服务,别离发放0-999尾号的数字,每次发号之后递增1000.这样做很简略,服务相互之间根本都不必通信,做好本人的事件就好了.

转自

https://www.kancloud.cn/marti…
欢送关注哦

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理