短网址(short URL)系统的原理及其实现

 https://mp.weixin.qq.com/s/khkJOJUw0ArxOdSQ6m-AGQ

URL短网址系统的算法设计及实践

在通常情况下,URL是由系统生成的,通常包括URI路径,多个查询参数,可以对参数进行加密和解密。当人们要分享某个URL,比如短信,邮件,社交媒体,这就需要短URL。

而短网址,顾名思义就是在长度上比较短的网址。简单来说就是帮您把冗长的URL地址缩短成8个字符以内的短网址。你有没有遇到过短信字符过长本来一条信息搞定的事情需要发两条?你有没有遇到过填报系统里填写网址却因为字符限制无法完整提交?你有没有遇到过排版好的内容由于链接过长而完全打乱了美感?这时候,你就需要用到短网址生成工具了。如开发者社区的某个链接:https://developer.jdcloud.com/article/894?mid=14
变成短网址后:w.3.cn/1000000xZ
我们可以看到,原URL从50多个字符,缩短为了10多个字符,跳转地址不会改变的同时,还能进行后台链接地址的数据追踪。非常便于消息通知、广告推广等场景中使用。
图片短网址是如何形成的?
通常情况下短网址的生成流程,分以下2条路径:图片
  • 从缓存中查询长网址是否已经生成过短网址,如果已经生成过,则直接返回缓存中的短网址,因为同一个长网址始终对应同一个短网址。

  • 从缓存中查询长网址是否已经生成过短网址,如果没有生成过,则使用算法生成一个短网址,然后保存短网址与长网址的关系,并判断是否碰撞,本案因采用了无碰撞递增算法,可直接返回短网址。

注意:此处市面上大多产品采用随机算法,存在很大的碰撞概率,如果缓存中已经存在了该短网址,就会重新生成,当并发极高的情况,碰撞率(新生成的短码在缓存中已存在,需要再次重新生的概率)也大大升高,就会形成一个死循环,如上图蓝色部分,极大的降低了性能。
图片分布式无碰撞短码生成算法短如果你经常使用短网址就会发现,市面接口生成性能普遍较差,同时生成大量短链时,可能会超时或失败。这是因为市面大多的算法是随机算法,碰撞率比较高,还有部分数据库自增算法,虽然无碰撞,但是过度依赖数据库导致性能比较差。而另外一种常遇到的情况是,生成的短链时不时的会出现出现短连接失效或链接内容无法追踪的情况。这是因为短链过期了,而我们的短网址只要在过期时间内有访问就会不断延期,达到有访问的连接永久有效,无访问的连接自动过期回收的效果。那么怎样才能避免上述情况的出现呢?我们通过采用缓存加内存的发号方式去对链接进行处理,实现了短链无碰撞且高性能的分布式无碰撞短码生成服务分布式无碰撞短码生成算法主要通过内存发号、缓存取号、保障机制三个主要环节来进行实现。

 

 

 
  • 绿色通道:内存发号,速度极快,每次从缓存取出10000个无重复号码,然后在内存中便可连续生成10000个短码,因此速度比传统基于数据库及缓存自增发号方式快万倍。

  • 蓝色通道:缓存取号,依赖缓存保证分布式发号无碰撞,批量发号,每一万次内存绿色通道才走一次蓝色缓存通道,因此性能极高

  • 红色通道:保障机制,保障生成的号码都在短网址对应长度的号码总容量范围内,仅在初始化及总容量用尽时执行,性能损耗可忽略不计。

通过该算法生成的短链主要有以下特点:1、有访问自动延期,无访问自动过期回收,可根据业务需要自行选择有效期,减少死码长期占用资源消耗费用,避免短码越积越多导致的碰撞率升高及性能下降2、自研专利算法、无碰撞率、只依赖缓存不依赖数据库,效率超高超稳定3、用户自定义域名、体现自有品牌价值、成本低廉、接入简单
图片实用操作指南
短网址服务目前在京东主要应用于:订单消息通知、物流通知、促销短信、二维码分享 等任何有字数限制的使用场景。微博、Twitter、消息推送、短信等都有单条发送字数的限制,以短信为例,单条发送限制70个字符。如果包含一个长网址(假设50个字符),则要传递的有效信息就只有20个字符,很容易表达不清,或超出70个字符产生2条短信费用。以我们一开始生成的链接为例:w.3.cn/1000000xZ短网址中分为域名host和短码部分,w.3.cn/1000000xZ中,w.3.cn为域名,1000000xZ为短码,短码长度可根据需求进行调整,对应不同的最大有效期。
长度 最大有效期(天) 备注
6 10 特殊场景开放
7 30  
8 100 默认长度
9 365  

最大有效期为当前长度下有效期可配置的最长时间,失效后将无法再使用,服务支持有访问时自动续期,需要传入有效期参数0,将自动配置为最大有效期同时有访问自动更新当前有效期为最大时间。

使用短网址服务可以把一个长网址缩短成短网址(假设20个字符),则要传递的有效信息就可以增长到50个字符,即能传递更多的有效信息,又能节省大量短信费用。因此,如何将长网址缩到最短,并且在高并发场景下保持高效率,至关重要。
你问我短码生成难不难?来!首先,打开浏览器输入网址short.jdcloud.com或直接点击【阅读原文】,输入长网址,然后点击生成即可。

图片

 
 

 

 

短网址(short URL)系统的原理及其实现 https://hufangyun.com/2017/short-url/

背景

提供一个短址服务
你有没有发现,我们的任务中出现长 URL 就会比较麻烦?如果有一个短址生成器就好了。虽然市面上有很多,但是我们可以重复发明一个轮子,利用这个机会尝试一下简单的 Web 全栈开发。

任务

做一个短链接生成器,可以将一个长链接缩短成一个短链接。

要发车了 🚌

发车前,和大家说一下

如果不想重复的造轮子,想开箱即用,可以使用基于 PHP 的开源软件 YOURLSYOURLS 还可以和 WordPress 整合到一起,功能强大,可扩展性高。

本文记录了开发短网址系统的整个过程,包括初期的算法调研、模块设计、数据库设计、功能扩展等。

什么是短链接 🔗

就是把普通网址,转换成比较短的网址。比如:http://t.cn/RlB2PdD 这种,在微博这些限制字数的应用里。好处不言而喻。短、字符少、美观、便于发布、传播。

百度短网址 http://dwz.cn/
谷歌短网址服务 https://goo.gl/ (需)号称是最快的 🚀

原理解析

当我们在浏览器里输入 http://t.cn/RlB2PdD 时

  1. DNS首先解析获得 http://t.cn 的 IP 地址
  2. 当 DNS 获得 IP 地址以后(比如:74.125.225.72),会向这个地址发送 HTTP GET 请求,查询短码 RlB2PdD
  3. http://t.cn 服务器会通过短码 RlB2PdD 获取对应的长 URL
  4. 请求通过 HTTP 301 转到对应的长 URL https://m.helijia.com 。

这里有个小的知识点,为什么要用 301 跳转而不是 302 呐?

301 是永久重定向,302 是临时重定向。短地址一经生成就不会变化,所以用 301 是符合 http 语义的。同时对服务器压力也会有一定减少。
但是如果使用了 301,我们就无法统计到短地址被点击的次数了。而这个点击次数是一个非常有意思的大数据分析数据源。能够分析出的东西非常非常多。所以选择302虽然会增加服务器压力,但是我想是一个更好的选择。

来自知乎 iammutex 的答案

算法实现

网上比较流行的算法有两种 自增序列算法、 摘要算法

算法一

自增序列算法 也叫永不重复算法

设置 id 自增,一个 10进制 id 对应一个 62进制的数值,1对1,也就不会出现重复的情况。这个利用的就是低进制转化为高进制时,字符数会减少的特性。

如下图:十进制 10000,对应不同进制的字符表示。

 

短址的长度一般设为 6 位,而每一位是由 [a - z, A - Z, 0 - 9] 总共 62 个字母组成的,所以 6 位的话,总共会有 62^6 ~= 568亿种组合,基本上够用了。

哈哈,这里附上一个进制转换工具 http://tool.lu/hexconvert/ 上图的数据就是用这个工具生成的。

具体的算法实现,自行谷歌。

算法二

  1. 将长网址 md5 生成 32 位签名串,分为 4 段, 每段 8 个字节
  2. 对这四段循环处理, 取 8 个字节, 将他看成 16 进制串与 0x3fffffff(30位1) 与操作, 即超过 30 位的忽略处理
  3. 这 30 位分成 6 段, 每 5 位的数字作为字母表的索引取得特定字符, 依次进行获得 6 位字符串
  4. 总的 md5 串可以获得 4 个 6 位串,取里面的任意一个就可作为这个长 url 的短 url 地址

这种算法,虽然会生成4个,但是仍然存在重复几率

两种算法对比

第一种算法的好处就是简单好理解,永不重复。但是短码的长度不固定,随着 id 变大从一位长度开始递增。如果非要让短码长度固定也可以就是让 id 从指定的数字开始递增就可以了。百度短网址用的这种算法。上文说的开源短网址项目 YOURLS 也是采用了这种算法。源码学习

第二种算法,存在碰撞(重复)的可能性,虽然几率很小。短码位数是比较固定的。不会从一位长度递增到多位的。据说微博使用的这种算法。

我使用的算法一。有一个不太好的地方就是出现的短码是有序的,可能会不安全。我的处理方式是构造 62进制的字母不要按顺序排列。因为想实现自定义短码的功能,我又对算法一进行了优化,下文会介绍。

流程图

自增序列算法流程图

 

开始输入网址查询数据库是否存在对应的短码返回对应的短码返回短网址结束保存输入的网址到数据库根据id计算对应的短码更新短码到数据库yesno

只实现长链接转化为短链接的功能,不是很麻烦。在调研的过程中我发现百度短网址可以自定义短码,我觉的这个功能挺不错,结果复杂度就是上图到下图的变化。😭

自增序列算法 + 用户自定义短码 流程图

 

开始输入网址用户输入的是短链接提示用户不能输入短链接结束查询数据库是否存在该URL返回短码返回短网址用户选择自定义短码短码是否存在提示用户该短码已存在更新短码到数据库根据id计算对应的短码短码是否存在查询数据库获得一条自定义短码的url对应的id记录yesnoyesnoyesnoyesnoyesno

百度短网址还允许用户自定义短码,算法二 摘要算法,不和 id 绑定,好像挺好实现这个功能的。

但是自增序列算法是和 id 绑定的,如果允许自定义短码就会占用之后的短码,之后的 id 要生成短码的时候就发现短码已经被用了,那么 id 自增一对一不冲突的优势就体现不出来了。

那么怎么实现自定义短码呐?

我是这样处理的:

数据库增加一个类型 type 字段,用来标记短码是用户自定义生成的,还是系统自动生成的。
如果有用户自定义过短码,把它的类型标记自定义。每次根据 id 计算短码的时候,如果发现对应的短码被占用了,就从类型为自定义的记录里选取一条记录,用它的 id 去计算短码。
这样既可以区分哪些长连接是用户自己定义还是系统自动生成的,还可以不浪费被自定义短码占用的 id

我保留了 1 到 2 位的 短码,从三位的短码开始生成的。就像域名的保留域名一样,好的要自己预留 😏

位数个数区间
1位 62 0 - 61
2位 3844 62 - 3843
3位 约 23万 3844 - 238327
4位 约 1400万 238328 - 14776335
5位 约 9.1亿 14776336 - 916132831
6位 约 568亿 916132832 - 56800235583

数据表设计

links 表

字段含义
id link_id
url 长连接
keyword 短链接码
type 系统: “system” 自定义: “custom”
insert_at 插入时间
updated_at 更新时间

后期功能扩展

统计:点击量、访问的 ip 地域、用户使用的设备

管理后台:删除、数据量

登录:权限管理

设置密码:输入密码才可以继续访问

项目源码

使用 Elixir + phoenix 技术栈 short_url

 

posted @ 2018-10-15 16:42  papering  阅读(3112)  评论(1编辑  收藏  举报