短链接生成算法的考虑方案

512 阅读5分钟

谷歌出的一个 MurmurHash 算法.

具体就是通过一种 Hash 函数生成原始链接对应的 10 进制数,再转化为 62 进制得到 6 个字符的一个短链接串, 通过拼接域名就得到了能访问的完整短链接。

6 位 62 进制数可表示 568 亿的数

image.png


由于 Sass 即软件即服务,以后给别人使用就需要把 API 给别人,所以就是短链接除了控制台创建,还有一种"接口创建"。因此专门放在另一个模块 project 里。

其他的哈希生成算法

参考链接:

自增序列 ID 算法

小黑盒应该问的就是为什么不用这个. 害没仔细看过.

  1. 首先看为什么是可行的

短链生成那里,可以用一个全局 id 生成器,生成自增 id 后再进行哈希运算然后转 62 进制? 毕竟判重只是判断域名+后缀是否重复,这样就不用转原始链接了? 甚至在哈希运算的速度上也会有提升吧?

还有只要来一个链接,直接生成一个 uuid,再转换一下得到后缀,貌似也行。

  1. 然后看为什么不行

自增 ID 生成:

  • 自增 id 生成,看样子很方便,你还可以根据当前生成到的序列值减去前段时间的序列值推断出这段时间内的短链接生成情况,做一个预测。
  • 但是你要知道这个自增 id 是有限的,你数字存储的长度一定是有限的,在后期的扩展上可能需要改为其他方法,主要一点,你还要维护整个系统这个 id 的状态,万一系统丢失了这些值或者延迟等问题,生成的短链接很大概率就会冲突,重新生成导致效率下降

UUID 方案:

  • 而对于 UUID 的方案,我居然突然觉得它是可行的,因为它生成的结果几乎没有重复,那就是说进行哈希运算的冲突也很低,既然刚才讲了,短链接的后缀生成和哈希运算的对象是什么样的无关,uuid 好像也是完全可以的。
  • 但是 UUID 的生成,是要进行算法计算的,比一般的 id 生成器的速度上更低,也就是说你在获取要进行哈希运算的对象上就落后了。

所以综上,我们直接把原始链接作为哈希的对象是更好的,前端都传过来了还再准备什么呢?是吧?

对于多次对于同一短链接的创建重复,我们可以临时加一个 UUID 作为后缀,无伤大雅。(加时间戳在极端情况下仍然会冲突)。


下面的我觉得更倾向于作为订单 id 等流水线 id 时会有的问题。所以下面这部分不太符合短链生成不采用的原因。

维护一个 ID 自增生成器,比如 1,2,3 这样的整数递增 ID,当收到一个长链转短链的请求时,ID 生成器为其分配一个 ID,再将其转化为 62 进制,拼接到短链域名后面就得到了最终的短网址.

如何设计这个 ID 生成器. 获取这个 ID

  1. UUID 实现

每来一个请求就分配一个 UUID, 也就是全局唯一的标识符嘛. 通过这个生成短链接, 基本就不会重复了. 但是 UUID 生成的 id 比较长, 并且是无序的, 在插入数据库时可能频繁导致页分裂 (就是分布不均匀), 影响性能.

  1. 用 Redis

Redis 单机理论上能接收 10 万加的请求, 就是说很足够了嘛, 而且如果实在不够的话, 可以增加几台重节点, 进行集群部署. 然后调用 Redis 的 incr 自增命令进行实现.

具体就是:

  • 通过给多个 redis 服务器规定不同的 ID 生成范围, 比如第一个服务器是 0 到 999999, 第二个服务器是 10000000 到 19999999. 这种形式.
  • 然后设置一个 key, 这个 key 拼接一个自增的 ID, 刚开始为 0, 然后对其进行哈希运算, 取模之后到某个 redis 服务器进行 id 的自增, 拿到 id 之后转为 62 进制.

但是这样需要考虑 redis 的持久化嘛, 因为总不能每次重启 redis,id 都需要重新开始自增, 那进行运算后得到的短链接就重复了.

  1. 雪花生成算法

也是一种 id 生成算法, 但是呢它比较依赖于这个时钟, 也就是系统时间嘛. 如果某台机器的时间倒退了 (慢了). 就可能出现 id 重复这种问题.