短URL连接系统

定义:  

  短网址(Short URL),顾名思义就是在形式上比较短的网址。但不知道有多少人像我同样,因为面试问道才知道有这种系统而对短链接原理好奇,从而进行进一步的研究。在Web 2.0的今天,不得不说,这是一个潮流。目前已经有许多相似服务(短网址服务,如今大部分微博、手机邮件提醒等地方已经有不少应用模式了,并占据了必定的市场),借助短网址您能够用简短的网址替代原来冗长的网址,让使用者能够更容易的分享连接。例如:http://t.cn/SzjPjA。mysql

  自从twitter推出短网址(shorturl),继之国内各大微博跟风,google公开goo.gl使用API,短网址之风愈演愈烈。不得不说这是一个新兴又一大热门web2.0服务。web

为何要这样作的,缘由我想有这样几点:面试

  一、微博限制字数为140字一条,那么若是咱们须要发一些链接上去,可是这个链接很是的长,以致于将近要占用咱们内容的一半篇幅,这确定是不能被容许的,因此短网址应运而生了。
  二、短网址能够在咱们项目里能够很好的对开放级URL进行管理。有一部分网址能够会涵盖暴力,广告等信息,这样咱们能够经过用户的举报,彻底管理这个链接将不出如今咱们的应用中,应为一样的URL经过加密算法以后,获得的地址是同样的。
  三、咱们能够对一系列的网址进行流量,点击等统计,挖掘出大多数用户的关注点,这样有利于咱们对项目的后续工做更好的做出决策。redis

短链接构成:

  协议+域名+参数算法

  例如:http://t.cn/SzjPjA 主要是参数:SzjPjA。这个是惟一标识。sql

短连接的好处:

  一、内容须要;数据库

  二、用户友好;浏览器

  三、便于管理。缓存

短链接用途:

  最简单的用途就是他的名字直译“短”的“连接”,能够把长长的一串连接(例如:亚马逊的购买连接)缩短成为几个简单的字符。服务器

短链接原理:

  短链接原理很是简单,就是用户访问短链接地址,到达咱们的短链接网站,而后网站经过短链接里的code,查询数据库获得原始url,而后让网页跳转到原始url便可。

  一、针对小型应用:
    1)经过发号策略,给每个过来的长地址,发一个号便可,小型系统直接用mysql的自增索引就搞定了。
    2)建立一张数据库表,仅须要有2列便可:code列和url列。code列也就是标识列,建议直接设置为自增主键。用于存储短链接参数代码,也就是短链接里的code。

  url列用于存储要跳转的原始url。

  二、针对大型应用:
    能够考虑各类分布式key-value系统作发号器。不停的自增就好了。第一个使用这个服务的人获得的短地址是http://xx.xx/0 第二个是 http://xx.xx/1 第11个是 http://xx.xx/a

   依次日后,至关于实现了一个自增字段便可。

  所说的连接推广分析功能,就是在这个过程当中,记录访客的某些信息,例如:访问时间、访问的短连接、访客的IP、访客的UserAgent信息等。基于这些信息,配合推广方式,就能够辅助判断出什么时间,什么范围,什么人群的推广更有曝光效果。

短连接实现方法:

面试时,个人回答:
  一、小型的就用数据库就好,利用自增ID做为参数;
  二、大型的也就是高并发的状况,使用redis这种k-v存储系统进行存储。个人思路以下:利用列表存储,每一个列表存储1万个数据;redis中每一个列表的key从1开始(也就是对1万作整除);若是想获得某个短连接对应的原地址,那就经过divmod函数进行计算,他的商就表明是第几个列表,余数表明他的位置。这样去获取。
  三、若是使用redis去实现的化,怎么保证你的系统内存不被撑爆?就是说我上一种存储机制是彻底把数据存放在内存中的!我当时的回答是每隔一段时间作一次持久化。
  四、内存的问题解决了,可是若是过一段时间我再来获取我存放的原url地址(假如我作持久化的时间是每隔12个小时,原数据已经存放到数据库中),这种状况怎么解决?我当时的回答是从数据表(表结构的设计是:原url,还有个num列)中批量获取一段数据,放入redis(可是这样的话就没有考虑高访问的状况,至关因而又把内存撑爆了)。

  五、并发的问题。

网上查找获得的解决方案:(由简入难)

第一种:
  26个大写字母 26小写字母,10个数字,随机生成6个而后插入数据库对应一个id,短链接跳转的时候,根据字符串查询到对应id,便可实现相应的跳转!不过2的62次方,不知道有没有重复的,小几率能够,可是对应不是很大的网站应该足够了。

第二种:
  经过发号策略进行存储
几个子问题:
一、如何用数据库或者KV存储来作?
  用10进制去记录。好比第10000个长地址,咱们给它的短地址对应的编号是9999,咱们经过存储自增拿到9999后,做为参数加到短连接以后;另外一种方式就是拿到这个数以后,再作一个进制转换,例如10进制转成16进制(晋级版的能够考虑加密)。

二、如何实现同一个长地址屡次转换,出来仍是同一个短地址?
  上面的发号原理中,是不判断长地址是否已经转过的。也就是说用拿着百度首页地址来转,我给一个http://xx.xx/abc 过一段时间你再来转,我还会给你一个 http://xx.xx/xyz。这看起来挺很差的,可是很差在哪里呢?很差在不是一一对应,而一长对多短。这与咱们完美主义的基因不符合,那么除此之外还有什么不对的地方?
  有人说它浪费空间,这是对的。同一个长地址,产生多条短地址记录,这明显是浪费空间的。那么咱们如何避免空间浪费,有人很是迅速的回答我,创建一个长对短的KV存储便可。嗯,听起来有理,可是。。。这个KV存储自己就是浪费大量空间。因此咱们是在用空间换空间,并且貌似是在用大空间换小空间。真的划算吗?这个问题要考虑一下。固然,也不是没有办法解决,咱们作不到真正的一一对应,那么打个折扣是否是能够搞定?
  这个方案最简单的是创建一个长对短的hashtable,这样至关于用空间来换空间,同时换取一个设计上的优雅(真正的一对一)。而实际状况是有不少性价比高的打折方案能够用。个人方案是:用key-value存储,保存“最近”生成的长对短的一个对应关系。注意是“最近”,也就是说,我并不保存全量的长对短的关系,而只保存最近的。好比采用一小时过时的机制来实现LRU淘汰。

这样的话,长转短的流程变成这样:
  1.0 在这个“最近”表中查看一下,看长地址有没有对应的短地址
  1.1 有就直接返回,而且将这个key-value对的过时时间再延长成一小时
  1.2 若是没有,就经过发号器生成一个短地址,而且将这个“最近”表中,过时时间为1小时
  因此当一个地址被频繁使用,那么它会一直在这个key-value表中,总能返回当初生成那个短地址,不会出现重复的问题。若是它使用并不频繁,那么长对短的key会过时,LRU机制自动就会淘汰掉它。
  固然,这不能保证100%的同一个长地址必定能转出同一个短地址,好比你拿一个生僻的url,每间隔1小时来转一次,你会获得不一样的短地址。这样作对整个短系统是没有影响的。

三、如何保证发号器的大并发高可用?
  上面设计看起来有一个单点,那就是发号器。若是作成分布式的,那么多节点要保持同步加1,多点同时写入,这个嘛,以CAP理论看,是不可能真正作到的。其实这个问题的解决很是简单,咱们能够退一步考虑,咱们是否能够实现两个发号器,一个发单号,一个发双号,这样就变单点为多点了?依次类推,咱们能够实现1000个逻辑发号器,分别发尾号为0到999的号。每发一个号,每一个发号器加1000,而不是加1。这些发号器独立工做,互不干扰便可。并且在实现上,也能够先是逻辑的,真的压力变大了,再拆分红独立的物理机器单元。1000个节点,估计对人类来讲应该够用了。若是你真的还想更多,理论上也是能够的。

四、具体存储如何选择?
  这个问题就不展开说了,各有各道,主要考察的是对存储的理解。对缓存原理的理解,和对市面上DB、Cache系统可用性,并发能力,一致性等方面的理解。

五、跳转用301仍是302?   这也是一个有意思的话题。首先固然考察一个候选人对301和302的理解。浏览器缓存机制的理解。而后是考察他的业务经验。301是永久重定向,302是临时重定向。短地址一经生成就不会变化,因此用301是符合http语义的。同时对服务器压力也会有必定减小。   可是若是使用了301,咱们就没法统计到短地址被点击的次数了。而这个点击次数是一个很是有意思的大数据分析数据源。可以分析出的东西很是很是多。因此选择302虽然会增长服务器压力,可是我想是一个更好的选择。

相关文章
相关标签/搜索