长链接:我们平常浏览器上面的那个链接就是长链接,也就是我们普通用的网址链接,像这种 https://zh.wikipedia.org/wiki/
为什么需要需要短链接?
长链接过长、形式更复杂,难以记忆、手动输入及流通不方便,导致长网址必须通过复制黏贴才能传播。因此,短链接的出现易于传播和记忆。
由于某些类似 Twitter 的微博客服务对于每条贴子或消息有字数限制(多为140字),某些文章超过一行78个字符时,也会造成一些会自动为网址加上超链接的 Telnet 及 BBS 软件无法正确执行该动作,因此需要通过短链接的功能来达到网址缩短的目的。
那么要实现这样的长链接转短链接在计算机层面是怎么做的呢?
实现方案
键值对应实现方案常有:
哈希算法
主键 id 自增法
先讨论几种方式再讨论上面的方案
1.实现一个算法,将长链接与短链接一一对应,再实现它的逆运算,再转换回长链接。
这个方法不可行的原因是你永远都找不到一一对应的运算,即使是现在的 hash 算法都会存在对撞的可能,假如你真的找到了一个一一对应的算法了,那 hash 就永远不会对撞了。
2.将长链接通过某个算法转换成短链接,将长短链接的关系存储到数据库中。通过短链接跳转的时候查找长链接,来重新定位到网页
转换到时候还是会有对撞问题,而且跳转时需要查找数据库需要查询时间,链接查找起来需要的耗时会比较多,还要维护链接的搜寻问题
现在回到上面的两个方法上
1.实现 hash 将长链接转换成短链接一一对应,存在 hash 对撞,通过对撞后的结果生成一条链表,对撞后直接链表查询,对于链表的查询需要做一些查询上的优化,hash 虽然降低了一些查询的成本,本质上还是要维护对撞后的链表查询。
2.主键id自增法,这个也是目前比较流行的方法,重点讲下这个方法和他的一些问题
主键id自增法
主键id自增法存在的一些问题
长链接与发号的号码在数据库中的存储问题
0x01 62 进制
字母 A-Z,a-z,0-9,组成的 62 进制。 例如 A 表示 0,9 表示 61。10 进制到 62 进制的转换可以参考 10 进制转成其他常见的进制,例如 八进制,十六进制,类比一下
一个长链接能否对应多个短链接的情况
这个问题也是比较棘手的问题,现在我没找到一一对应的方法,每转换一个长链接就会发一个号,同一个链接多次转换的话就会导致一个长链接对应多个短链接的情况,如果避免这种情况,每次转换时查表,又需要很长时间。如果使用长对短 key- value 存储又会消耗空间,多存一条数据也是空间,建立长对短的 key-value 存储也消耗空间,都是在用空间换时间,key-value 存储时消耗的空间指不定会比你多存一些数据要大,空间上不划算
优化方式
使用固定大小的 LRU 缓存,存储最近 N 次的映射结果,如果某一个链接生成的非常频繁,则可以在 LRU 缓存中找到结果直接返回。
0x02 LRU 算法
最先使用的会被保留,最后使用的会被淘汰,假如只能缓存 3 个链接的话,假设有 3 条链接已经转换,<维基百科链接,百度链接,新浪链接>,那如果我现在再转一次维基百科的链接,他就会变成 <百度链接,新浪链接,维基百科链接>,当有新的链接进来时,比如推特链接,那缓存里面就需要淘汰一个链接,那就是百度的链接了,就会变成这样<新浪链接,维基百科链接,推特链接>
分布式系统时,如何保证发号机发的号不重复
假如有 100 个发号机,每个发号机可以分别发尾号为 0-99 的号,每发完一个号,发号机直接 100 ,例如尾号 99 的发号机,发完 99 号之后,第二个号发 199,这样可以避免重复发号的问题。
还有就是用 Twitter 的雪花发号器, SnowFlake 算法可以生成 64 位的ID,刚好可以用 long 整型存储,能够用于分布式系统中生产唯一的ID,(0 – 41 时间戳 42-46 数据中心标识 47-51 机器标识 52-63 序列号)
跳转时是用 301 还是 302 的问题
301是永久重定向,而302是临时重定向
References:
长 URL 转短 URL [Ref] https://juejin.cn/post/6844903853830176776
SnowFlake[web] https://www.snowflake.com
301,302 和 Google 排名[blog] https://ahrefs.com/blog/zh/301-vs-302-redirects/