想必经常收到这样的短信。短信中的链接一般都是短链接,类似于下图这样,这就是短地址,而
而当我打开改短地址时,则发生重定向到长地址,如下图所示
短地址与长地址是一一对应还是一对多还是多对多?显然一个短地址对应一个长地址才是合理的,那这里我们需要自己封装或者寻找一个可以实现长短地址一一映射的函数,最好还能有从还能保持反向转换的能力。但是很遗憾,这样的算法不存在。那么怎么才能实现一对一呢?正确的思路是建立一个发号器,每次有一个新的长URL进来,我们就增加一。其实数字是一对一的,只要一个地址不存在,就给他一个自增的数字,如下图所示,那这么就实现了长地址与短地址的一一对应关系。
我们返回的短URL一般是将数字转换成32进制,这样子可以更加有效的缩短URL长度。但是32进制的数字对计算机来说只是字符串,怎么存储呢?直接存储字符串对等值查找好找,对范围查找等太不友好了。 其实可以直接存储10进制的数字,只需要在业务逻辑层加一个进制转换的函数即可。这样不仅占用空间少,对查找的支持较好,同时还可以更加方便的转换到更多/更少的进制来进一步缩短URL。如下图所示。
当浏览器中访问www.yuming.cn/3oi0时,我们是可以获取3oi0参数的,然后对该参数进行解析10进制为123456,去数据库中查询123456的记录,就获取到原长地址URL,那这样数据库中也就不用去存短地址了。如下图所示。
很多时候我们依赖的是MySQL做发号器,每一次发号都需要访问一次MySQL来获取当前的最大号码,并且在获取之后更新最大号码,这个压力是比较大的。但是当发请求增大,对数据库的压力太大,可能会造成瓶颈。这里有两种思路。
批量发号(单点服务): 我们可以每次从数据库获取10000个号码,然后在内存中进行发放,当剩余的号码不足1000时,重新向MySQL请求下10000个号码.在上一批号码发放完了之后,批量进行写入。这样可以将对数据库持续的操作移到代码中进行,并且异步进行获取和写入操作,保证服务的持续高并发。 分布式发号(分布式服务): 上面设计的系统是有单点的,那就是发号器是个单点,容易挂掉。 可以采用分布式服务,分布式的话,如果每一个发号器进行发号之后都需要同步给其他发号器,那性能其实也得不到保证。假设我们有两个发号器,一个发单号,一个发双号,发号之后不再是递增1,而是递增2。
性能&统计: 使用 301 虽然可以减少服务器的压力,但是无法在 server 层获取到短网址的访问次数了,如果链接刚好是某个活动的链接,就无法分析此活动的效果以及用于大数据分析了。 而 302 虽然会增加服务器压力,但便于在 server 层统计访问数,所以如果对这些数据有需求,可以采用 302,因为这点代价是值得的,但是具体采用哪种跳转方式,还是要结合实际情况进行选型。