短网址服务系统设计

2019-10-14  本文已影响0人  爱情小傻蛋

短网址 顾名思义,就是将长网址缩短到一个很短的网址,用户访问这个短网址可以重定向到原本的长网址(还原)。这样可以达到易于记忆、转换的目的,常用于有字数限制的微博、二维码等场景。
开篇先抛出几个问题,如果大家自己去实现会怎么实现这个看似很简单的服务呢?

1.是否有什么算法可以直接把一百个字符左右的长网址缩短到10位以内,并可以原样还原,即可逆。

10倍的压缩比在无损压缩算法领域谁介绍下?当然这个比例是基于多样数据而不是特定的文本,否则文本只有一个字符a,那压缩比想多少有多少。

2.只实现字符压缩/hash,不需要做到可逆,然后存储到数据库中,恢复时只需要查询数据库。

从压缩的角度和第一条说明没有区别,不可能无损压缩,那就有可能出现hash碰撞。不同的长网址缩短成了同一个短网址,那也做不到还原了。

3.接着第二条,出现碰撞了可以后面再加随机字符。

随机字符可以缓解碰撞问题,但是无法根治。另外,增加几位字符呢才可靠呢?这种概率事件无法通过测试来回答,通过运维监控不断的调整也是一件头疼和折磨人的事。

4.预先在redis/db里异步生成一批短码,每次从列表里面取不就好了。

具体是在redis还是db里批量生成其实是截然不同的两种实现。 若是redis, 那么里面要放入全量的短码么?否则怎么知道这个短码到底是不是唯一的?如果全量,那对redis的可用性就要严格保证,否则它挂了,就必须全量的预热,这个过程要做好不是那么的容易; 若是db, 那么就要有大量的并发锁定,意味着大量读写,这个对数据库也是个考验。

5.短网址的还原跳转用301还是302呢?

301是永久重定向,302是临时重定向。短地址一经生成就不会变化,所以用301是符合http语义的。同时浏览器会对301请求保存一个比较长期的缓存,这样就减轻对服务器的压力;而且301对于网址的SEO有一定的提升。但是很多情况下我们需要对接口点击或者用户行为进行一些业务监控处理的时候,301明显就不合适了(浏览器直接按照缓存数据跳转了), 所以很多业务场景下还是采用302比较合适。

缩短网址的算法

初期选型算法

对于算法本人也算是踩了不少的坑,最开始采用的是网上流传甚广的微博短网址算法(原理类似16进制与62进制的转换),加了些许改进:

算法其实并不太复杂,大家自行解读。这个算法在服务量不大的情况下hash碰撞的概率尚可以接受,一定量的压测效果也还算理想。因为有4个hash可选项,即使碰撞到了还有其他3次机会去避免。但是如果作为基础服务,在使用方调用量级无法估量无法保证短链接绝对可用的情况下,这个算法还是有很大的隐患!

改进算法

只要有hash就有碰撞的可能,要一劳永逸就得抛弃hash算法。这里我们就用全局自增长的10进制序号 -> 62进制实现。这里继续抛出问题来了:

Redis/DB 如何设计

DB设计

只需要一张表,存放短码与原网址的映射关系,其他一些属性比如原网址的sha1码,过期时间等保存好即可。当然短码和sha1字段都要加上唯一索引,保证唯一性的同时提高查询效率。

Redis设计

若想短链接服务达到低延迟高并发的目标,Redis在很多环节都可以起到关键作用。

  1. 自增长序列
    通过Redis的 incr 方法可以很容易的实现全局自增长序列,但前提是Redis的高可用,如果Redis挂了序列从哪里开始呢?当然是从DB中拿咯,怎么拿?
  1. 长网址的Hash表
    在Redis中存入热点网址的hash映射数据,注意,这里说的是热点网址而且不是全量网址,实现者需要有所取舍。或者没有命中的就产生新的短码(会导致同址不同码),或者没有命中就到数据库查询,保证强一致的同址同码。

  2. 短码与长网址的映射表
    同样,在Redis中存入热点网址的映射,在短网址还原的请求处理中可以快速的查询到原网址。所以这个点的缓存是必须的。

其他一些说明

上一篇 下一篇

猜你喜欢

热点阅读