短网址服务的核心功能,就是把原始的长网址转化成短网址;当用户点击短网址的时候,短网址服务会将浏览器重定向为原始网址。
哈希算法生成短网址
哈希算法可以将一个不管多长的字符串,转化成一个长度固定的哈希值。
生成短网址,不需要考虑反向解密的难度,只需要关心哈希算法的计算速度和冲突概率。
MurmurHash算法提供了两种长度的哈希值,一种是32bits,一种是128bits。对原始网址进行hash计算之后,得到的哈希值再品尚短网址服务的域名,就构成最终的短网址。
让短网址更短
将10进制的哈希值,转化成更高进制的哈希值。
16进制中,用A~E来表示10~15。在网址URL中,常用的合法字符有0~9、a~z、A~Z这样62个字符。so将10进制的哈希值转化成62进制。(10进制除以62取余,余数相应字符)
解决哈希冲突问题
一般情况下,保存短网址跟原始网址之间的对应关系(数据库),以便后续用户在访问短网址的时候,可以根据对应关系,查找到原始网址。
当有一个新的原始网址需要生成短网址的时候,先利用MurmurHash算法生成短网址,然后拿生成的短网址在数据库中查找。如果没有找到相同的短网址,表明此短网址没有冲突,将对应关系存到数据库,并将短网址返回给用户。
如果在数据库中找到了相同的短网址,将其对应的原始网址也取出来,跟正在处理的原始网址对比,相同则直接用;若不同则说明发生哈希冲突。
给原始网址拼接一串特殊的字符(DUPLICATED),重新计算哈希值,极端情况再次出现冲突就继续拼接字符串。最终把哈希值和原始网址拼接了特殊字符串之后的文本分别存在数据库中。
当用户访问短网址的时候,短网址服务先通过短网址在数据库中查找对应的原始网址。如果原始网址中有凭借特殊字符,就先将特殊字符去掉再返回给浏览器。
优化哈希算法性能
给短网址字段添加B+树索引。提高通过短网址查询原始网址的速度。
在短网址生成的过程中,会跟数据库打两次交到,执行两条SQL语句。
通过短网址查询短网址与原始网址的对应关系;将新生成的短网址和原始网址之间的对应关系存储到数据库。
给数据库中的短网址字段添加唯一索引。当有新的原始网址需要生成短网址时,直接将生成的短网址与对应的原始网址尝试存储到数据库中。如果数据库能将数据正常写入,则说明没有违反唯一索引,新生成的短网址没有冲突。如果范围违反唯一索引异常,则按正常的“查询-写入过程”。
将已经生成的短网址构建成布隆过滤器。当有新的短网址生成的时候,先拿短网址在布隆过滤器中查找。如果查找的结果是不存在的,说明没有冲突,只需要执行写入的SQL语句。
ID生成器生成短网址
维护一个ID自增生成器,可以生成自增的整数ID。当短网址服务接收到一个原始网址转化成短网址的请求之后,它先从ID生成器中取一个号码,然后将其转化成62进制表示法,拼接到短网址服务的域名后面,就形成了最终的短网址。最后将生成的短网址和对应的原始网址存储到数据库中。
相同的原始网址可能会对应不同的短网址
每次新来一个原始网址,就生成一个新的短网址,会导致两个相同的原始网址生成了不同的短网址。解决方案:
不做处理。相同的原始网址对应不同的短网址,可以接受。大部分短网址的应用场景中,用户只关心短网址能否正确的跳转到原始网址,并不关心短网址长什么样。同一个原始网址,两次生成的短网址不一样,并不会影响到用户的使用。
借助哈希算法生成短网址的处理思想。要给一个原始网址生成短网址的时候,先拿原始网址在数据库中查找,看数据库中是否已经存在相同的原始网址。若存在就取出对应的短网址,直接返回给用户。
需要给数据库中的短网址和原始网址两个字段都添加索引。
高性能ID生成器
低性能:数据库自增字段、计数器等。
高性能:
借助Disruptor的思想,给ID生成器装多个前置发号器。批量的给每个前置发号器发送ID号码。当接收到短网址生成请求时,就选择一个前置发号器来取号码,通过多个前置发号器,提高并发发号能力。
实现多个ID生成器同时服务。为了保证每个ID生成器生成的ID不重复。要求每个ID生成器按照一定的规则,生成ID号码。(第一个ID生成器只能生成尾号为0的ID,第二个只能生成尾号为1的ID,以此类推)。