另辟蹊径--自增短链ID设计

 

自增短链ID设计

一、前言

前几年因为微博的兴起,用户在分享网址的时候,因为微博长度限制,造成了很多不便,所以URL长短链转换技术开始火爆起来。

同样作为市场营销推广的CPS广告链接,如果url太长,也会影响到推广效果。这就需要使用短链转换进行推广了。

下面的内容就是我在做短链方案的时候研究的一些问题,和最终确认的技术方案,采用了一些和网上主流方案不同的技术。

二、技术分类

目前网络上各大短链转换系统,采用的算法从大方面可以分为两类:

2.1、内容压缩算法

使用算法直接对长链内容进行压缩,例如获取hash算法,或者采用MD5算法,将长连接生成一个128bit的特征码,然后将特征码截取成48位用作短链码。

2.2、发号器算法

不考虑长链的内容,通过发号策略,给每一个过来的长地址,发一个号即可。例如使用mysql,每个地址加入系统那么主键id自增,使用主键作为短链码。

 

三、优缺点分析

3.1MD5压缩算法

目前业界普遍采用的短链算法,因为MD5         可以针对任何文本生成一个唯一的特征码,同时碰撞的概率很低,两个不同的文本有可能但是几率很小会生成同样的特征码。

 

优点:生成简单;因为一个文本只有一个对应的MD5码,所以支持长链重复查询。

 

缺点:因为是有损压缩算法,无限的可能对应到有限的字符,不可避免会有重复。重复的概率虽然低,但是在大数据量面前就是必然会发生。(之前流量系统的短链算法因为MD5碰撞的问题,需要做额外的程序处理)

3.2、自增id算法

采用给每个长链接一个ID号,解决了有损压缩和重复的问题,但是因为递增id会造成很大的缺陷。同时因为在大数据量的情况下,新来一个长连接我们不可能通过查询数据库的方式来确认是否已经在数据库存在,因为超长字段在数据库很难被索引,这样就会造成长链接重复。

 

优点:根据有限的长链生成有限的id,不会重复。

 

缺点:自增id暴率在外,有很大的安全风险,造成链接信息泄露;不支持长链接重复查询。

3.2、对比分析

综合上面的分析,我们就清楚了为什么普遍采用MD5生成长连接。因为相对于发号器的缺点,如果链接数量不是非常大的情况下,MD5重复的概率是非常小的,而且可以采用程序逻辑解决。

但是对于强迫症的我们来说,MD5压缩算法合情,但不合理;特别是短链接数量到了一定的程度,这种重复碰撞会变得越来越频繁。

如同生日重复悖论一样,如果一个房间里有23个或23个以上的人,那么至少有两个人的生日相同的概率要大于50%

 

而自增ID的方式恰好满足了我们的强迫症理念,唯一的长链进来,获取唯一的短链码,,不用再去考虑随机和概率,以及无限的可能性。如果能够使用各种手段解决其它的各种缺陷,那么不就完美了吗?

 

 

四、流程详解

4.1、长链接重复查询问题

为了解决已经入库的长链接,下次再查询的问题,我们可以借鉴MD5短链的原理。直接把长链的MD5结果作为特征码存入数据库,下次再来一个长链接的时候我们再生成MD5特征码然后去数据库查询;

例如,有以下数据:

182126_Ux6B_2485991.jpg

   四条链接,其中前两条拥有相同的MD5特征码,那么我们再来新链接的时候根据新链接的MD5特征码假设还是XXX。去查数据库得到两条记录,再详细比对长链接,如果不同那么新增一条记录,如果相同,则返回相同的那条记录。

 

4.2、主键id泄露问题

      主键ID泄露这是最严重的问题,直接影响到发号器算法能否使用。主键id数据因为是规律递增的,所以外在特征非常明显。那么我们就要想办法进行处理,隐藏掉id的特征,并且使得外部用户无法反向获得数据库的主键id

隐藏递增规律的核心就是使用Feistel 密码结构:

Feistel加密算法的输入是长为2w的明文和一个密钥K=K1K2...,Kn)。将明文分组分成左右两半LR,然后进行n轮迭代,迭代完成后,再将左右两半合并到一起以产生密文分组。

Feistel加密算法能够产生一个非常好用的特点,那就是,在一定的数字范围内(2n次方),每一个数字都能根据密钥找到唯一的一个匹配对象,这就达到了我们隐藏递增规律的目的。

例如,我们给定数字范围为6426次方),其中,每个数字都能找到唯一一个随机对应的数字对。这里的随机通过密钥来产生。

182214_Uwmv_2485991.jpg

那么我们将12使用算法进行计算,会发现对应到的数字就是1725。这就完美解决了我们的数字递增问题,外部用户无法从数字表面看出是递增的。而且每个数字的匹配模式都不一样。

Feistel加密,我们可以简单的使用其中的变换流程,代码如下:

182604_7EcF_2485991.jpg

其中permutedId方法就是加密主方法,round是根据参数和密钥生成一个随机数,达到随机匹配的效果,使得每个数字的匹配模式都不一样。

最神奇的是此加密方法是可逆的,如果permutedId(a)=b,那么必然会有permutedId(b)=a

 

4.3、数字压缩和加密

解决了数字递增问题之后,那么我们需要做的就是数字压缩和加密了,毕竟10进制的主键数字,如果用来支持短链,长度还是过长。

由于使用主键递增来作为短链id,所以压缩对象仅仅是数字,数字的压缩是最简单的。我们可以采用多进制的方式进行长度压缩,这里我们采用62进制来处理。

为什么选择62进制,因为一个符号位,如果我们采用不带符号的简单字符表示,09数字,az小写字母以及AZ大写字母,加起来总共62个常用字符。

进制转换代码如下:

182730_ghmJ_2485991.jpg

 

进制转换算法原理就是循环除以62取模,每一次取到的模就是62进制的每一位数字,假设我们的主键id通过Feistel转换之后得到数字为28469255853通过上面的方法,最后我们得到了一个数组:

[31,4,42,5,60,1]

     这个数组就是62进制的对象,然后通过字符串密钥,生成相应的字符,假设第一位数字的密钥为“tcd8WPqMLVYEgDspfwX4xQo5SFbNHIa3mAierCUkv61hR2079ZzGKnTyjBJOlu

     则获取其中的第31个字符,得到小写字母a

     同理根据不同位数各自的密钥,最终我们得到的62进制数为:a8QZEj

     这就是我们最终得到的短链id

4.4、新短链码特性

    最后分析一下这个短链码的特点,例如上面生成的o8QZEj

1)这个id每一位字符与实际数字的对应关系都不同,因为每一位都是使用不同的密钥字符串来转换的。

2)外部用户完全得不到短链码之间的递增关系,例如主键1= Xzlqio ;主键2= hoyqsA

3)长短链是一对一的关系,同一个长链获取到的短链码必然相同,同一个短链码也必然对应同一个长连接。

4)容量大,6位的短链码,因为自增特性,完全无重复。可以容纳626次方= 568亿个短链,这是其它任何算法无法达到的;如果扩大位数到7位,则可以支持35200亿!

 

五、实测

下图是实际生成短链码的截图:

182929_A8G0_2485991.jpg

循环生成6个短链码,其中id写在数组,得到的结果如下:

         Atwhnp6   LepYjsy   XivTmCH   9zBwAUx  dsUuGgA  oYcQzMs   Np8HNHq

六、总结

自增id加上数字变换、数字压缩、字符加密等技术,很好的解决了短链id生成的一些问题,弥补了传统MD5算法的缺点,同时又拥有自身的各种优势。适合应用在数据来量大的长短链转换业务中。

平时在网上获取的、行业内普遍使用的方案不一定是最好的方案;实际业务中想到达到更好的性能和效果需要不断的尝试各种技术,实际进行使用和分析;这样才能获得最适合我们的方案。

转载于:https://my.oschina.net/u/2485991/blog/613920

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值