短网址有啥利益,用长网址不香吗?-千亿国际娱乐网站

 成功案例     |      2022-06-27 13:15
本文摘要:前言今天,我们来谈谈如何设计一个高性能短链系统,短链系统设计看起来很简朴,但每个点都能展开许多知识点,也是在面试中很是适合考察候选人的一道设计题,本文将会联合我们生产上稳定运行两年之久的高性能短链系统给大家简朴先容下设计这套系统所涉及的一些思路,希望对大家能有一些资助。

千亿国际娱乐网站

前言今天,我们来谈谈如何设计一个高性能短链系统,短链系统设计看起来很简朴,但每个点都能展开许多知识点,也是在面试中很是适合考察候选人的一道设计题,本文将会联合我们生产上稳定运行两年之久的高性能短链系统给大家简朴先容下设计这套系统所涉及的一些思路,希望对大家能有一些资助。本文将会从以下几个方面来解说,每个点包罗的信息量都不少,相信大家看完肯定有收获:短链有啥利益,用长链不香吗短链跳转的基本原理短链生成的几种方法高性能短链的架构设计注:内里涉及到不少布隆过滤器,snowflake 等技术,由于不是本文重点,所以建议大家看完后再自己去深入相识,否则展开讲篇幅会很是非链有啥利益,用长链不香吗来看下以下极客时间发我的营销短信,点击下方蓝色的链接(短链)浏览器的地址栏上最终会显示一条如下的长链。

那么为啥要用短链表现,直接用长链不行吗,用短链的话有如下利益1、链接变短,在对内容长度有限制的平台发文,可编辑的文字就变多了最典型的就是微博,限定了只能发 140 个字,如果一串长链直接怼上去,其他可编辑的内容就所剩无几了,用短链的话,链接长度大大淘汰,自然可编辑的文字多了不少。再好比一般短信发文有长度限度,如果用长链,一条短信很可能要拆分成两三条发,原来一条一毛的短信费酿成了两三毛,何苦呢。另外用短链在内容排版上也更雅观。

2、我们经常需要将链接转成二维码的形式分享给他人,如果是长链的话二维码麋集难识别,短链就不存在这个问题了,如图示3、链接太长在有些平台上无法自动识别为超链接如图示,在钉钉上,就无法识别如下长链接,只能识别部门,用短地址无此问题短链跳转的基本原理从上文可知,短链利益多多,那么它是如何事情的呢。我们在浏览器抓下包看看可以看到请求后,返回了状态码 302(重定向)与 location 值为长链的响应,然后浏览器会再请求这个长链以获得最终的响应,整个交互流程图如下主要步骤就是会见短网址后重定向会见 B,那么问题来了,301 和 302 都是重定向,到底该用哪个,这里需要注意一下 301 和 302 的区别301,代表 永久重定向,也就是说第一次请求拿到长链接后,下次浏览器再去请求短链的话,不会向短网址服务器请求了,而是直接从浏览器的缓存里拿,这样在 server 层面就无法获取到短网址的点击数了,如果这个链接恰好是某个运动的链接,也就无法分析此运动的效果。所以我们一般不接纳 301。

302,代表 暂时重定向,也就是说每次去请求短链都市去请求短网址服务器(除非响应中用 Cache-Control 或 Expired 表示浏览器缓存),这样就便于 server 统计点击数,所以虽然用 302 会给 server 增加一点压力,但在数据异常重要的今天,这点代码是值得的,所以推荐使用 302!短链生成的几种方法1、哈希算法怎样才气生成短链,仔细视察上例中的短链,显然它是由牢固短链域名 + 长链映射成的一串字母组成,那么长链怎么才气映射成一串字母呢,哈希函数不就用来干这事的吗,于是我们有了以下设计思路那么这个哈希函数该怎么取呢,相信肯定有许多人说用 MD5,SHA 等算法,其实这样做有点杀鸡用牛刀了,而且既然是加密就意味着性能上会有损失,我们其实不体贴反向解密的难度,反而更体贴的是哈希的运算速度和冲突概率。能够满足这样的哈希算法有许多,这里推荐 Google 出品的 MurmurHash 算法,MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。与其它盛行的哈希函数相比,对于纪律性较强的 key,MurmurHash 的随机漫衍特征体现更良好。

非加密意味着着相比 MD5,SHA 这些函数它的性能肯定更高(实际上性能是 MD5 等加密算法的十倍以上),也正是由于它的这些优点,所以虽然它泛起于 2008,但现在已经广泛应用到 Redis、MemCache、Cassandra、HBase、Lucene 等众多著名的软件中。画外音:这里有个小插曲,MurmurHash 成名后,作者拿到了 Google 的 offer,所以多做些开源的项目,说不定成名后你也能不经意间收到 Google 的 offer ^_^。MurmurHash 提供了两种长度的哈希值,32 bit,128 bit,为了让网址尽可通地短,我们选择 32 bit 的哈希值,32 bit 能表现的最大值近 43 亿,对于中小型公司的业务而言绰绰有余。

对上文提到的极客官链做 MurmurHash 盘算,获得的哈希值为 3002604296,于是我们现在获得的短链为 牢固短链域名+哈希值 = http://gk.link/a/3002604296如何缩短域名?有人说人这个域名还是有点长,另有一招,3002604296 获得的这个哈希值是十进制的,那我们把它转为 62 进制可缩短它的长度,10 进制转 62 进制如下:于是我们有 (3002604296)10 = (3hcCxy)10,一下从 10 位缩短到了 6 位!于是现在获得了我们的短链为 http://gk.link/a/3hcCxy画外音:6 位 62 进制数可表现 568 亿的数,应付长链转换绰绰有余如何解决哈希冲突的问题?既然是哈希函数,不行制止地会发生哈希冲突(只管概率很低),该怎么解决呢。我们知道既然会见会见短链能跳转到长链,那么两者之前这种映射关系一定是要生存起来的,可以用 Redis 或 Mysql 等,这里我们选择用 Mysql 来存储。

表结构应该如下所示CREATE TABLE `short_url_map` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `lurl` varchar(160) DEFAULT NULL COMMENT '长地址', `surl` varchar(10) DEFAULT NULL COMMENT '短地址', `gmt_create` int(11) DEFAULT NULL COMMENT '建立时间', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;于是我们有了以下设计思路。将长链(lurl)经由 MurmurHash 后获得短链。再凭据短链去 short_url_map 表中查找看是否存在相关记载,如果不存在,将长链与短链对应关系插入数据库中,存储。

如果存在,说明已经有相关记载了,此时在长串上拼接一个自界说好的字段,好比「DUPLICATE」,然后再对接接的字段串「lurl + DUPLICATE」做第一步操作,如果最后还是重复呢,再拼一个字段串啊,只要到时凭据短链取出长链的时候把这些自界说好的字符串移除即是原来的长链。以上步骤显然是要优化的,插入一条记载居然要经由两次 sql 查询(凭据短链查记载,将是非链对应关系插入数据库中),如果在高并发下,显然会成为瓶颈。画外音:一般数据库和应用服务(只做盘算不做存储)会部署在两台差别的 server 上,执行两条 sql 就需要两次网络通信,这两次网络通信与两次 sql 执行是整个短链系统的性能瓶颈所在!所以该怎么优化呢首先我们需要给短链字段 surl 加上唯一索引当长链经由 MurmurHash 获得短链后,直接将是非链对应关系插入 db 中,如果 db 里不含有此短链的记载,则插入,如果包罗了,说明违反了唯一性索引,此时只要给长链再加上我们上文说的自界说字段「DUPLICATE」,重新 hash 再插入即可,看起来在违反唯一性索引的情况下是多执行了步骤,但我们要知道 MurmurHash 发生冲突的概率是很是低的,基本上不太可能发生,所以这种方案是可以接受的。

固然如果在数据量很大的情况下,冲突的概率会增大,此时我们可以加布隆过滤器来举行优化。用所有生成的短网址构建布隆过滤器,当一个新的长链生成短链后,先将此短链在布隆过滤器中举行查找,如果不存在,说明 db 里不存在此短网址,可以插入!画外音:布隆过滤器是一种很是省内存的数据结构,长度为 10 亿的布隆过滤器,只需要 125 M 的内存空间。综上,如果用哈希函数来设计,总体的设计思路如下用哈希算法生成的短链其实已经能满足我们的业务需求,接下来我们再来看看如何用自增序列的方式来生成短链2、自增序列算法我们可以维护一个 ID 自增生成器,好比 1,2,3 这样的整数递增 ID,当收到一个长链转短链的请求时,ID 生成器为其分配一个 ID,再将其转化为 62 进制,拼接到短链域名后面就获得了最终的短网址,那么这样的 ID 自增生成器该如何设计呢。

如果在低峰期发号还好,高并发下,ID 自增生成器的的 ID 生成可能会系统瓶颈,所以它的设计就显得尤为重要。主要有以下四种获取 id 的方法1、类 uuid简朴地说就是用 UUID uuid = UUID.randomUUID(); 这种方式生成的 UUID,UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机械上生成的数字,它保证对在同一时空中的所有机械都是唯一的,但这种方式生成的 id 比力长,且无序,在插入 db 时可能会频繁导致页破裂,影响插入性能。

2、Redis用 Redis 是个不错的选择,性能好,单机可支撑 10 w+ 请求,足以应付大部门的业务场景,但有人说如果一台机械扛不住呢,可以设置多台嘛,好比我部署 10 台机械,每台机械划分只生成尾号0,1,2,... 9 的 ID, 每次加 10 即可,只要设置一个 ID 生成器署理随机分配给发号器生成 ID 就行了。不外用 Redis 这种方案,需要思量持久化(短链 ID 总不能一样吧),灾备,成本有点高。

3、Snowflake用 Snowflake 也是个不错的选择,不外 Snowflake 依赖于系统时钟的一致性。如果某台机械的系统时钟回拨,有可能造成 ID 冲突,或者 ID 乱序。

4、Mysql 自增主键这种方式使用简朴,扩展利便,所以我们使用 Mysql 的自增主键来作为短链的 id。简朴总结如下:那么问题来了,如果用 Mysql 自增 id 作为短链 ID,在高并发下,db 的写压力会很大,这种情况该怎么办呢。思量一下,一定要在用到的时候去生成 id 吗,是否可以提前生成这些自增 id ?方案如下:设计一个专门的发号表,每插入一条记载,为短链 id 预留 (主键 id * 1000 - 999) 到 (主键 id * 1000) 的号段,如下发号表:url_sender_num当长链转短链的请求打到某台机械时,先看这台机械是否分配了短链号段,未分配就往发号表插入一条记载,则这台机械将为短链分配规模在 tmp_start_num 到 tmp_end_num 之间的 id。

从 tmp_start_num 开始分配,一直分配到 tmp_end_num,如果发号 id 到达了 tmp_end_num,说明这个区间段的 id 已经分配完了,则再往发号表插入一条记载就又获取了一个发号 id 区间。画外音:思考一下这个自增短链 id 在机械上该怎么实现呢, 可以用 redis, 不外更简朴的方案是用 AtomicLong,单机上性能不错,也保证了并发的宁静性,固然如果并发量很大,AtomicLong 的体现就不太行了,可以思量用 LongAdder,在高并发下体现越发优秀。

整体设计图如下解决了发号器问题,接下来就简朴了,从发号器拿过来的 id ,即为短链 id,接下来我们再建立一个是非链的映射表即可, 短链 id 即为主键,不外这里有个需要注意的地方,我们可能需要防止多次相同的长链生成差别的短链 id 这种情况,这就需要每次先凭据长链来查找 db 看是否存在相关记载,一般的做法是给长链加索引,但这样的话索引的空间会很大,所以我们可以对长链适当的压缩,好比 md5,再对长链的 md5 字段做索引,索引就会小许多。这样只要凭据长链的 md5 去内外查是否存在相同的记载即可。

所以我们设计的表如下CREATE TABLE `short_url_map` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '短链 id', `lurl` varchar(10) DEFAULT NULL COMMENT '长链', `md5` char(32) DEFAULT NULL COMMENT '长链md5', `gmt_create` int(11) DEFAULT NULL COMMENT '建立时间', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;固然了,数据量如果很大的话,后期就需要分区或分库分表了。高性能短链的架构设计在电商公司,经常有许多运动,秒杀,抢红包等等,在某个时间点的 QPS 会很高,思量到这种情况,我们引入了 openResty,它是一个基于 Nginx 与 Lua 的高性能 Web 平台,由于 Nginx 的非阻塞 IO 模型,使用 openResty 可以轻松支持 100 w + 的并发数,一般情况下你只要部署一台即可,不外为了制止单点故障,两台为宜,同时 openResty 也自带了缓存机制,集成了 redis 这些缓存模块,也可以直接连 mysql。

不需要再通过业务层连这些中间件,性能自然会高不少如图示,使用 openResty 省去了业务层这一步,直达缓存层与数据库层,也提升了不少性能。总结本文对短链设计方案作了详细地剖析,旨在给大家提供几种差别的短链设计思路,文中涉及到挺多像布隆过滤器,openResty 等技术,文中没有展开讲,建议大家转头可以再详细相识一下。

再好比文中提到的 Mysql 页破裂也需要对底层使用的 B+ tree 数据结构,操作系统按页获取等知识有比力详细地相识,相信大家各个知识点都吃透后会收获不小!(完)。


本文关键词:短,网址,有啥,利益,用长,不香,吗,千亿,国际,千亿国际娱乐网站

本文来源:千亿国际娱乐网站-www.huaruijiban.com