前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >东半球最接地气的短链接系统设计

东半球最接地气的短链接系统设计

作者头像
Java3y
发布于 2019-11-12 06:29:00
发布于 2019-11-12 06:29:00
66100
代码可运行
举报
文章被收录于专栏:Java3yJava3y
运行总次数:0
代码可运行
本文公众号来源:孤独烟

作者:孤独烟

引言

今天下午,烟哥和同事在厕所里排队等坑的时候(人多坑少)。想象一下一个场景,我正在一边排队,一边拿着手机撩妹。前面一个同事,拿着手机短信转过头来和我聊天。

于是,我们就开始讨论下面这种短链接的实现原理(没错,上厕所也不忘学习!)。

点击其中短链接后,我们会跳到如下地址http://h5.dangdang.com/mix_20191015_or4x本文,我们来讨论一下其实现原理!

正文

需求缘起

这里说一下,为什么需要短链接?这个简单,比如大家发微博有字数限制

如果 URL 地址过长,显然可以写的关键字就越少!

再比如发短信如果短信内容过长,那么一条短信就要拆成两条发,浪费钱!

因此采用短链接,不仅节约资源,还十分美观!

请求流程

首先,我们先看看当当的短链接http://dwz.win/nXR

它是由两个部分组成

  1. http://dwz.win:短链接系统的域名地址
  2. nXR:请求参数

请求http://dwz.win/nXR地址后,返回状态如下所示

于是,我们可以推断出,敲下http://dwz.win/nXR地址后,发生了什么呢?

这里渣渣烟就要多嘴一句了。上图所示短链接系统,返回的状态可以为 301 或者 302,只是当当网用的是 301。

这里我要说一下,大家应该明白30X状态,在 HTTP 协议中,代表的是重定向的状态。那么301和302区别在哪呢,继续往下看。

301 代表什么?

301 代表的是永久重定向。什么意思呢? 对于 GET 请求, 301 跳转会默认被浏览器 cache。也就是说,用户第一次访问某个短链接后,如果服务器返回 301 状态码,则这个用户在后续多次访问同一短链接地址,浏览器会直接请求跳转地址,而不会再去短链接系统上取!

这么做优点很明显,降低了服务器压力,但是无法统计到短链接地址的点击次数。

302 代表什么?

302 代表的是临时定向。什么意思呢? 对于 GET 请求, 302 跳转默认不会被浏览器缓存,除非在 HTTP 响应中通过 Cache-Control 或 Expires 暗示浏览器缓存。因此,用户每次访问同一短链接地址,浏览器都会去短链接系统上取。

这么做的优点是,能够统计到短地址被点击的次数了。但是服务器的压力变大了。

下面说最关键的一段,怎么将http://h5.dangdang.com/mix_20191015_or4x压缩为nXR字符

算法原理

首先呢,我们需要一张表来存储,长短链接间的映射关系。表结构如下

列名

说明

id

BIGINT,自增主键

url

长地址,也就是需要跳转的原地址

好的,假设我们此时表里的数据如下

id

url

1

http://h5.dangdang.com/mix_20191015_or4x

2

http://h5.dangdang.com/mix_20191102_ad3x

我们此时拿自增 id 作为短链接的 key。假设域名http://dwz.win是短链接系统,也就是说请求:

  • (1)http://dwz.win/1会跳转http://h5.dangdang.com/mix_20191015_or4x;
  • (2)http://dwz.win/2会跳转http://h5.dangdang.com/mix_20191102_ad3x;

这么做,也不是不行,有两个缺点你要评估能不能接受!

  • (1)如果数据比较大,比如几百亿,你的 url 地址依然过长
  • (2)你的数据具有规律性,别人用一个简单的脚本就可以遍历出你的跳转地址!

为了解决上面的两个缺点,我们增加一个列,用来存储 key 值。此时表结构如下

列名

说明

id

BIGINT,自增主键

key

短串,需要加唯一索引

url

长地址,也就是需要跳转的原地址

我们为了缩短 id 的长度呢,一般可以这么做。由于我们的短链接是由 a-z、A-Z 和 0-9 共 62 个字符可以选择。因此,我们可以将十进制的数字 id,转换为一个 62 进制的数,例如 201314 就可以转换为 Qn0。算法如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final String BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

public static String toBase62(long num) {
    StringBuilder sb = new StringBuilder();
    do {
        int i = (int) (num % 62);
        sb.append(BASE.charAt(i));
        num /= 62;
    } while (num > 0);

    return sb.reverse().toString();
}

另外,我们需要引入一个全局发号器,一直返回全局自增的 ID。相当于,我们的短链接系统先去请求这个全局自增 ID,然后将全局自增 ID 转换为 62 进制的数,作为 key。

接下来,解决第二个问题!数据具有规律性的问题。毕竟你转换为 62 进制后,只是解决了数据过长的问题,数据规律性问题还是没解决。因此,我们需要引入一个随机算法。

那么此时,你的考虑点在于,你是否要根据 key 值,反推出全局 id 值!来抉择不同的随机算法!

(1)不希望反推出全局 ID

OK,那就用一个洗牌算法,打乱算出的值。比如十进制的 201314 就可以转换为 Qn0。然后再使用洗牌算法,可以返回 n0Q、Q0n....其中之一。但是会有一定几率冲突,多洗几次就行。

(2)希望反推出全局 ID

OK,那就在得到 Qn0 这个数字后,将其转换为二进制数。然后在固定位,第五位,第十位...(等等)插入一个随机值即可。至于如何反推也很简单,你拿到短链接 key 后,将固定位的数字去除,再转换为十进制即可。

讲到这里,就基本将 key 如何生成的逻辑讲清楚了。那么用户在点击短链接的时候,例如地址http://dwz.win/nXR,短链接系统解析出 key 为 nXR,根据唯一索引去表中将 nXR 对应的 url 返回即可。

细节优化

(1)分库分表

如果这个系统是放在公网,给大家使用的。建议上来就分库分表,数据量过 1000 万是很容易的。这里涉及到一个问题,拿全局发号器给的自增 id 做分片健,还是拿转换后的 key 做分片键。

显然,用转换后的 key 做分片键会更容易一些。如果用 ID 做为分片键,存在两个问题!

  1. 用户请求的 key,需要做一个逆运算推算回 ID,然后根据 ID,再去对应表里去找,增加响应时间。
  2. 根据选择的随机算法不同,key 不一定能够推算回 ID 值。这种情况下,只能每张表去查,更慢。

所以用 key 做分片键,再适合不过了。拿到用户请求的 KEY 后,直接定位到对应的表里将 url 取出即可。

(2)读写分离

这种系统显然,读远大于写。建议可以考虑做读写分离。

(3)引入缓存

假设,我们在一个时间,给手机推送短信链接的短信后。显然,后面的一段时间内,对该短链接的请求量会大大提升。没有必要每次都去数据库查询,因此可以引入 redis 缓存。

(4)全局发号器

用其他算法行不行 ?可以。这里只是要一个全局唯一 ID 而已。自己要估算好,使用其他算法所带来的性能影响。以及采用其他算法,会不会造成生成的生成的 ID 过于规律。

(5)防攻击

做好被恶意攻击的准备,防止自增 ID 的值,被全部耗光

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java3y 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
让Nginx 支持 ASP ASP.NET配置方法
nginx 作为世界顶级轻量WEB服务器。越来越受到网站开发者的喜欢了。国内大的网站 也都纷纷采用nginx作为生产环境。
用户1685462
2021/07/18
5.2K0
Nginx负载均衡
在大型网站中,负载均衡是有想当必要的。尤其是在同一时间访问量比较大的大型网站,例如网上商城,新闻等CMS系统,为了减轻单个服务器的处理压力,我们引进了负载均衡这一个概念,将一个服务器的压力分摊到几个服务器上,一方面减轻了宕机的几率,另一方面也使得宕机后还要其他服务器可以继续稳定运行,提高了系统的健壮性。
业余草
2019/01/21
1.1K0
Nginx负载均衡
opensuse nginx+mono 2.8支持aspx环境的配置
nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的门户网站及搜索引擎Rambler(俄文:Рамблер)使用。  其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页伺服器中表现较好.Nginx 超越 Apache 的高性能和稳定性,使得国内使用 Nginx 作为 Web 服务器的网站也越来越多,其中包括
张善友
2018/01/30
4.4K0
借助Nginx搭建反向代理服务器
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
java架构师
2019/02/26
3.2K0
Nginx
Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率 。它支持内核Poll模型,能经受高负载的考验,有报告表明能支持高达 50,000个并发连接数。
框架师
2021/04/16
5780
Nginx
nginx+iis实现负载均衡
用户1168362
2018/01/05
2.5K0
nginx+iis实现负载均衡
Nginx负载均衡与反向代理
一、nginx配置属性详细说明: #全局设置 main  # 运行用户 user www-data;     # 启动进程,通常设置成和cpu的数量相等 worker_processes  1; # 全局错误日志及PID文件 error_log  /var/log/nginx/error.log; pid        /var/run/nginx.pid; # 工作模式及连接数上限 events {     use epoll; #epoll是多路复用IO(I/O Multiplexing)中的一种方
Sindsun
2018/04/28
9830
Nginx负载均衡与反向代理
【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器
一、反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从
小小科
2018/05/02
1.5K0
【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器
Windows下Nginx负载均衡实现
2.配置nginx  打开nginx.conf文件 在http模块内添加 upstream 模块,插入 
星哥玩云
2022/07/25
8090
Windows下Nginx负载均衡实现
nginx 实现Web应用程序的负载均衡
文章转载自 博客园, 原文地址 http://www.cnblogs.com/ivanyb/archive/2011/11/16/2250710.html
乔达摩@嘿
2020/09/11
1.3K0
nginx 实现Web应用程序的负载均衡
Linux下的.NET之旅:第一站,CentOS+Mono+Xsp构建最简单的ASP.NET服务器
  由于Linux/Unix等有更强的安全性、运行效率高、拥有大量优秀的开源组件,而.Net则有着其他语言无与伦比的开发效率,因此在非微软平台下运行.Net程序的需求很强烈。Mono 是一个由Novell 公司发起、并且得到微软支持的开源项目。Mono 项目可以在Linux,FreeBSD,Unix,Mac OS X 、Android和苹果系统等非微软操作系统下兼容运行.Net程序。目前占IOS游戏应用市场55%份额的游戏都是使用基于Mono的Unity3d技术开发的。    基于Mono让ASP.Net开发的网站运行在Linux操作系统下也已经有了大量成功的案例,比如世界著名的网站“维基百科WikiPedia ”的搜索部分就是使用Mono支撑运行的、Mozilla开发者社区也是基于Mono运行,可以看http://www.mono-project.com/Companies_Using_Mono  这一些使用Mono进行开发的公司的列表。让.Net脱离Windows的禁锢,在开源的世界中尽情的徜徉。
Edison Zhou
2018/08/20
1.4K0
Linux下的.NET之旅:第一站,CentOS+Mono+Xsp构建最简单的ASP.NET服务器
在腾讯云上单机使用Nginx负载均衡发布网站
恕我见识短浅,不知道Nginx有Windows版本,可以运行在Windows系统下,当初遇到Socket并发压力增长,学习负载均衡的时候,找的是LVS的4层负载均衡,没有考虑7层负载均衡,所以一直不了解Nginx的Windows版本。今天写此教程,就是为了告诉大家怎么在Windows下配置Nginx。
opengps
2019/03/25
3K0
nginx实现负载均衡和动静分离
这篇文章主要为大家详细介绍了nginx实现负载均衡和动静分离,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
菲宇
2019/06/12
5290
在Ubuntu中配置ASP.NET站点
mono是.NET在Linux等非Windows平台上的第三方实现,借助它就可以实现.NET的跨平台应用。虽然mono还不能支持所有的.NET应用,但对于普通的小型程序,mono已经足够胜任了。更让人鼓舞的是当前最为流行的桌面Linux系统Ubuntu已经集成了mono的运行环境,只要手上有一个.net应用程序,拷贝到Ubuntu中,然后就可以运行了。实际上,在Ubuntu中,已经有一些应用程序是用C#完成的,例如附件中的便签程序Tomboy就是用C#写的,打开Tomboy的文件目录,就会发现很多在Windows中常见的dll程序集,所以,跨平台也不是不可以的。
用户1685462
2021/07/28
1.8K0
FastDFS蛋疼的集群和负载均衡(十四)之Nginx+Tomcat负载均衡
Interesting things 今天来配置一下Nginx+Tomcat负载均衡环境。 image.png What did you do today 什么是虚拟
用户2032165
2018/06/05
6460
Nginx反向代理和负载均衡配置
Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的。从2004年发布至今,凭借开源的力量,已经接近成熟与完善。
用户5706463
2019/07/21
1.3K0
在.NET Core之前,实现.Net跨平台之Mono+CentOS+Jexus初体验
本文介绍如何在.NET Core之前实现.NET跨平台,通过使用Mono、CentOS和Jexus服务器。首先,本文介绍了如何更新系统并安装Mono所需的库和GDI+兼容API的库Libgdiplus。然后,讲解了如何安装和配置Jexus服务器,并介绍如何部署ASP.NET Web应用程序。最后,总结了部署过程中的关键步骤和注意事项。
GuZhenYin
2018/01/04
9060
在.NET Core之前,实现.Net跨平台之Mono+CentOS+Jexus初体验
ASP.NET Core跨平台技术内幕
ASP.NET Core设计初衷是开源跨平台、高性能Web服务器,其中跨平台特性较早期ASP.NET是一个显著的飞跃,.NET现可以理直气壮与JAVA同台竞技,而ASP.NET Core的高性能特性更是成为致胜法宝。
有态度的马甲
2020/04/16
1.2K0
ASP.NET Core跨平台技术内幕
(转载非原创)Nginx的安装和部署
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
xlj
2021/07/17
4140
Nginx负载均衡配置与使用
现在Nginx到处都可以见到,经常会看到宕机后的网页会显示nginx的字样,这也说明Nginx由于高性能、使用配置简、开源单这些特点被越来越多的用户所接受,所使用。
Java帮帮
2018/12/24
7990
推荐阅读
相关推荐
让Nginx 支持 ASP ASP.NET配置方法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档