什么是URL短链

URL 短链,就是把原来较长的网址,转换成比较短的网址。以下面这条短信为例:

上图中,https://dx.10086.cn/looGDg 就是一条短链。用户点击蓝色的链接,就可以在浏览器中看到它对应的原网址:

http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx

为何要使用短链?先来看看短链能带来哪些好处:

  • 内容平台上(如微博、Twitter、小红书等),往往发文有长度限制,短链带来的好处不言而喻: 网址短、美观、便于发布、传播,能写更多正文了;

  • 短信,如果超过字数限制,就会被拆成多条发送,如果短信量大也可以省下不少钱;

  • 二维码,本质上也是一串 URL,长链的话二维码密集难识别,而短链则不会存在这种问题;

  • 安全性,不想过于直观的暴露原始网址;

  • 统一经过平台重定向,能对数据进行运营分析

短链跳转的原理

我们还是以上面的短链为例,原理如图:

流程可以分为三步:

第一步:浏览器发起请求,请求地址:https://dx.10086.cn/looGDg

第二步: 短链服务器收到请求后,通过短链接地址找到原始长链接。返回http状态码是301或302,同时也通过 location 响应头告知客户端:你要访问的其实是下面这个长网址:http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx

第三步: 客户端收到短链服务器的应答后,再跳转至长网址:http://wap.zj.10086.cn/case/mould/produce/9b032ecfcb9b42f6a8fc411d160d91e320200722001_750.html?chid_code=9c6d64&WT.mc_id=20210205zthgcsdx

实际浏览器中的网络请求如下图

这里简单回顾一下http状态码301和302的区别:

  • 301,代表 永久重定向,也就是说第一次请求拿到长链接后,下次浏览器再去请求短链的话,不会向短网址服务器请求了,而是直接从浏览器的缓存里拿,在 server 层面就无法获取到短网址的点击数了,如果这个链接刚好是某个活动需要统计点击率,那结果只可能是0或1了。所以一般不采用 301。

  • 302,代表 临时重定向,也就是说每次去请求短链都会去请求短网址服务器,便于 server 统计点击数。虽然用 302 会给 server 增加一点压力,但是更符合业务需要,所以推荐使用 302。

短链场需求分析

短链服务需求分析:

功能性需求:

  • 原始URL转短链
  • 访问短链跳转到原始URL
  • 短URL访问过期
  • 短URL非法失效
  • 自定义短链接
  • 短链的批处理
  • 访问统计
  • 支持B端多租户

非功能性需求:

  • 高可用:支持分布式服务下的高可用
  • 高性能:无论是生成短链,还是访问短链,服务都要支持高并发、低延时
  • 安全性:短链不可被预测,避免接口被轮询导致数据泄露等风险

系统容量预估

读写估算、存储估算、带宽估算、内存估算、缓存估算、总体估算:

存储预估:

  1. 假设,系统接入的某个业务一天生成 100万短链接。那么一年下来预估为:100万*30 *12 = 3.6亿
  2. 假设短链需要保存五年,且类似体量业务接入10个。存储五年的量预估为: 3.6* 5 * 10=180亿数据量
  3. 假设一条核心数据(长URL、短URL、创建时间和过期时间等信息)大小为0.5kb。那么存储180亿短链所需:180 * 0.5KB = 18T

读写预估:

假设这一百万数据需要在一小时内发完,那么我们单机能承受负载可以这么来估算:

  • 每秒写请求:

1000000 / 1 hour* 60 min * 60 sec = 278(Req/S)

  • 每秒读请求(读多写少,我们按照读写100 : 1 来考虑):

278 * 100 = 27800 (Req/S)

缓存预估:

缓存这部分计算可以参照读写请求的预估值,考虑业务的集中访问时间进行衡量。另外,如上文所提的场景,读远高于写的请求可以考虑加内存缓存,命中率会非常的高,这样对读性能又是一个显著提升。

短链长度预估:6位,可使用 短链 568亿

详细设计

短链生成算法

设计短链生成算法,本质就是找到f(x),寻找“长”、“短”之间的映射关系,这就是短链算法的根本。

方案1:Hash 算法

首先,最容易想到的就是MD5、SHA等算法。

输入的长 URL 经过 MD5 算法的处理,会输出一串长度为 128 bit 的字符串。128 bit 的 MD5 通过 Base62的规则编码(A-Za-z0-9),会生成22位的字符串。显然22位还是太长了。那么如何拿到6位短链呢?

首先想到截取,假设按照转换出来截取它的前六位或者后六位,两个完全不一样的长链转换出来的字符它的前6位或者后6位一样的概率还是很高的。就会导致上面的“关系”错乱,两个长链对应了一个短链上。

另外有同学会说,在发现冲突的时候加随机或者加时间戳,或者加IP等等。方案改进可以降低冲突概率,但是还是会存在。如果冲突一直在,就要重复执行这段逻辑。

可以看出MD5这种方式不是很优雅,而且在效率上也不高。

方案2:自增序列算法

区别于Hash算法,全局自增ID方案的好处是不需要关心原始长链接。天然支持一对一这种映射关系。不会存在之前Hash方案中一对多这种问题。

所以初步的想法通过一个ID自增生成器,可以通过数据库ID自增、zookeeper计数或者 redis的 incby或者自己实现一个自增计数器都行。程序收到请求后去拿一个ID,然后将这个ID通过Base62转换成短链,然后插入这个映射关系。

但是方案2会存在以下几个问题。

问题1:每次来一个请求,比如说长链是一样的。那势必也会生成一个ID。那如果有人刷接口或者重复提交,那很快ID资源将会耗尽。

问题2:如果是自增的ID,规律性太强,很容易被人预测,导致信息泄露。

该如何解决这些问题呢。

首先是问题1,可以通过对长链加唯一索引解决,但是会加大存储空间,另一面因字段内容过多会导致数据库page记录减少,当发生插入或者删除等操作很容易产生分页,影响性能。所以可以考虑用 布隆过滤器(Bloom Filter),当长链不存在时程序才给分配。

问题2相对容易一点,可以增加一些随机性,在规则上做一些操作。比如加上数据中心,机器IP等,而不是简单的加一加二。

所以综上考虑使用 Snowflake + Bloom Filter 来解决核心算法问题。篇幅有限,如果不清楚细节的可以自行深入了解下。

架构设计

整体架构如图。自上而下,首先网络层,在Nginx做读写域名分离,考虑到响应、安全等问题,创建、访问统计、详情等请求走内网域名,访问短链跳转走公网域名。

整个短链中心结构大体分为三层,系统安全、应用安全及业务处理。首先请求进入限流中心,规则基于服务流控、业务线流控及租户维度流控,当系统发生异常时我们可动态调节系统流控,保证整体系统的稳定,提供能力。当某个业务线或者某个租户出现异常流量或者被刷等情况之后,我们可以考虑对某个租户限制访问,限制该租户的请求,避免连锁反应,导致系统崩盘。安全中心将对进入的短链进行一些规则校验,比如长度、字符内容等,如一些非法恶意的请求直接做拦截处理。

如果该请求是创建等接口,将会对传入的Appkey和AppSecret进行鉴权校验,如果校验通过,基于短链生成算法,生成短链接,存储到数据库,完成数据主从集群备份,同时异步更新到Redis缓存集群并且加载到内存缓存,同时更新到过滤中心服务。如果该请求是访问查询请求,程序将先判断该短链是否在布隆过滤器内。若存在,则先走内存缓存然后Redis最终到DB,中间存在则立即返回;若不存在,则直接认定为非法短链。所以过滤中心非常重要,是维稳下层中间件安全的核心能力,防止异常流量对缓存或者数据库造成压力,进而引起雪崩。

数据库表结构设计

短链表设计核心字段如下:

保障系统稳定性

作为一个基础组件,必须要保证高并发的同时,还要考虑服务的稳定性及高可用。

首先是安全:

在服务上线之初,需要考虑几点。接口分类上大体分成两类,第一类是用户可以访问的短链接,另一类是用户无需感知且不能被感知的比如创建、查看详情、访问统计等等。首先要做的就是做好网络隔离,将用户可以访问的提供公网访问,不可访问的将网络限制机房或者办公网访问等。其次,接入的业务方需要分配指定的Appkey和AppSercert,核心接口调用进行必要的签名校验。防止一些恶意攻击流量对系统造成影响。

其次是限流:

为了让系统更加的健壮,这个时候就要考虑一些限流策略。可以针对整个服务或者接口做一些限流策略,可以基于Guava的 RateLimiter或者在网关层做一些限制。防止业务流量飙升的时候,保证服务是稳定可用的。

最后就是防刷:

首先过滤掉一批非法请求,将传入的短链进行正则检验,不满足直接过滤。满足校验规则,通过布隆过滤器,如果外部请求某个短链不存在系统中,那直接过滤掉,避免一些恶意的请求进入到系统造成影响。短链需要考虑接入一些安全服务,对长链内容进行一些检测,防止涉黄涉暴等内容发生,封禁之后影响整个域名的可用性。所以需要在设计之初,考虑快速拉黑失效短链的能力。

总结

本文详细介绍了短链的设计方案,阐述了短链设计原理、容量评估、具体设计方案及稳定性等方面的内容。我们基于业务场景需求分析,针对如何设计一款基础好用的短链服务这一话题进行了讨论。笔者基于文中原理使用Go语言编写了一套短链服务,在性能及稳定性上都有很强的表现。目前该服务已接入多个业务,线上运行稳定,逐步取代原先的单体服务。

想要开发一款基础服务,在功能、性能和安全上都必须进行多方位考虑。文中简要提到了 布隆过滤器、SnowFlake、Mysql 页分裂等技术,有兴趣的开发者们可以持续关注。

本文对短链服务设计做了详细地剖析,旨在给大家提供短链设计思路。如果你正在设计或者考虑设计一款短链服务,希望本文对你有所帮助。

技术干货 | 高性能短链设计与实现相关推荐

  1. 技术干货 | 为高音质保驾护航 - 通信中的回声消除

    导读:语音通信,在当代生活已经成为了大家主要的沟通交流方式,而通话语音的质量也是衡量每个厂商系统好坏的标志之一.这次给大家分享网易云信是如何通过回声消除算法保证通话语音质量的. 文|胡林艳 网易云信音 ...

  2. 还在烦恼高性能网关设计?看这文就够啦!

    作者 | 码海 来源 | 码海 之前的高性能短链设计一文颇受大家好评,共被转载 「47」 次,受宠若惊,在此感谢大家的认可!在文末简单提了一下 OpenResty,一些读者比较感兴趣,刚好我们接入层网 ...

  3. 如何设计一个高性能短链系统?

    目录 前言 短链有啥好处,用长链不香吗 短链跳转的基本原理 短链生成的几种方法 1.哈希算法 如何缩短域名 如何解决哈希冲突的问题? 2.自增序列算法 高性能短链的架构设计 总结 前言 今天,我们来谈 ...

  4. 【技术干货】40页PPT分享万亿级交易量下的支付平台设计

    本文主要是根据作者在2018QCon演讲内容整理而成: 苏宁金融交易量3年内从1000亿增长到万亿+,服务用户3亿+,服务场景从服务于苏宁易购内部生态,扩展到服务全渠道,全场景,多业态的线上线下智慧零 ...

  5. 【网易云信获奖啦】2020 年值得再读一遍的技术干货 | 下篇

    12 月 22 日,SegmentFault 思否发布中国技术先锋年度评选 | 2020 中国技术品牌影响力企业榜单,网易云信入选榜单. 感谢 SegmentFault 思否对网易云信在开发者生态上的 ...

  6. 消息推送技术干货:美团实时消息推送服务的技术演进之路

    本文由美团技术团队分享,作者"健午.佳猛.陆凯.冯江",原题"美团终端消息投递服务Pike的演进之路",有修订. 1.引言 传统意义上来说,实时消息推送通常都是 ...

  7. 飞凌嵌入式丨2020年技术干货合集大放送!

    亲爱的飞凌用户们 你们好哇 魔幻的2020即将过去 今年有些特殊,有些不容易 回看射雕处,千里暮云平 想必大家都有成长有收获 感谢你们一路以来的支持 2021即将到来 回顾2020 你是不是又博学了呢 ...

  8. 淘宝直播技术干货:高清、低延时的实时视频直播技术解密

    本文由淘宝直播音视频算法团队原创分享,原题"5G时代|淘宝直播高画质低延时技术探索",收录时有改动. 1.引言 目前,5G技术应用正在逐步推进,相比目前广泛使用的4G, 它具有更高 ...

  9. Arm云游戏及虚拟化技术沙龙,Arm中国,NVIDIA,腾讯及百度等为你分享超强技术干货...

    申耀的科技观察 读懂科技,赢取未来! 2021年3月24日,由Arm中国.竞核联合主办的"芯潮澎湃 云启未来"Arm云游戏及虚拟化技术沙龙在上海圆满落幕. Arm中国市场及生态副总 ...

最新文章

  1. 人工智能机器学习区别计算机应用,AI、人工智能和机器学习有什么区别
  2. 实用插件_这些实用的PR插件你知道吗?
  3. 互联网男士穿搭推荐-2020年新版
  4. java某个类避免findbug检查_Findbugs能否在java中检测到捕获RuntimeException?
  5. SSIS package 更新 variable
  6. ERROR 6: GEOS support not enabled.
  7. 管天管地管空气!谷歌探索用CV估算空气质量
  8. 【免费毕设】asp.netERP客户关系系统设计(源代码+lunwen)
  9. 为什么戏说php,PHP语言之戏说PHP框架的味道
  10. python实现将子文件夹下的图片复制到新的文件夹并重命名
  11. [容易]合并排序数组
  12. java工程师的职业规划_Java工程师如何进行职业规划?
  13. Java基础知识➣发送Emai和访问MySQL数据库(七)
  14. 卸载精灵(bue directx) r4.0 完美版 是什么
  15. 对称加密算法 Blowfish 和 Twofish
  16. 1080p和1080i
  17. ubuntu16.10+cuda8.0+cudnn+caffe+opencv3.2+anaconda2
  18. AtCoder Beginner Contest 164 E Two Currencies Bellman-Ford优化思想+01背包+动归dp状态转移
  19. 倒看北斗星---念霍去病
  20. netty源码分析及优点

热门文章

  1. Mysql初始化root密码和允许远程访问
  2. Oracle数据库权限管理
  3. Docker swarm - 使用体验 1+2
  4. 实训九(游戏退出按钮的实现)
  5. mysql merge表介绍
  6. 2015年10月15日学习html基础笔记
  7. c# treeView 取消选择事件
  8. 【郭林专刊】10个步骤让你成为高效的Web开发者
  9. 29final关键字
  10. 【MySQL随手记】字符集编码的查看、指定与修改语句