点击上方蓝色“方志朋”,选择“设为星标”

回复“666”获取独家整理的学习资料!


https://juejin.im/post/6844903873950269454

想必大家也经常收到垃圾短信吧...短信中的链接一般都是短链接,类似于下图这样:

为什么这里面的URL都是短的呢?有什么好处呢?怎么做到的呢?

短URL的好处

  1. 短信和许多平台(微博)有字数限制 ,太长的链接加进去都没有办法写正文了.

  2. 好看。 比起一大堆不知所以的参数,短链接更加简洁友好.

  3. 方便做一些统计。 你点了链接会有人记录然后分析的.

  4. 安全。 不暴露访问参数.

这就是为什么我们现在收到的垃圾短信大多数都是短URL的原因了.

那么短URL是怎么做到的呢?

短URL基础原理

短URL从生成到使用分为以下几步.

  1. 有一个服务,将要发送给你的长URL对应到一个短URL上.例如www.baidu.com -> www.t.cn/1

  2. 把短URL拼接到短信等的内容上发送.

  3. 用户点击短URL,浏览器用301/302进行重定向,访问到对应的长URL.

  4. 展示对应的内容.

本文主要集中于第一步,即如何将一个长URL对应到短URL上.

服务设计

如果你在往长短URL真实的对应关系上想,那么就走远了.

最理想的情况是: 我们用一种算法,对每一个长URL,唯一的转换成短URL.还能保持反向转换的能力.

但是这是不可能的,如果有这样的算法,世界上的所有压缩算法都可以原地去世了.

正确的思路是建立一个发号器,每次有一个新的长URL进来,我们就增加一,并且将新的数值返回.第一个来的URL返回"www.x.cn/0",第二个返回"www.x.cn/1".

接下来以QA形式写几个小问题:

对应关系如何存储?

这个对应数据肯定是要落盘的,不能每次系统重启就重新排号,所以可以采用mysql等数据库来存储.而且如果数据量小且qps低,直接使用数据库的自增主键就可以实现.

如何保证长短链接一一对应?

按照上面的发号器策略,是不能保证长短链接的一一对应的,你连续用同一个URL请求两次,结果值都是不一样的.

为了实现长短链接一一对应,我们需要付出很大的空间代价,尤其是为了快速响应,我们可以需要在内存中做一层缓存,这样子太浪费了.

但是可以实现一些变种的,来实现部分的一一对应, 比如将最近/最热门的对应关系存储在K-V数据库中,这样子可以节省空间的同时,加快响应速度.

短URL的存储

我们返回的短URL一般是将数字转换成32进制,这样子可以更加有效的缩短URL长度,那么32进制的数字对计算机来说只是字符串,怎么存储呢?直接存储字符串对等值查找好找,对范围查找等太不友好了.

其实可以直接存储10进制的数字,这样不仅占用空间少,对查找的支持较好,同时还可以更加方便的转换到更多/更少的进制来进一步缩短URL.

高并发

如果直接存储在MySQL中,当并发请求增大,对数据库的压力太大,可能会造成瓶颈,这时候是可以有一些优化的.

缓存

上面保证长短链接一一对应中也提到过缓存,这里我们是为了加快程序处理速度.可以将热门的长链接(需要对长链接进来的次数进行计数),最近的长链接(可以使用redis保存最近一个小时的)等等进行一个缓存,保存在内存中或者类似redis的内存数据库中,如果请求的长URL命中了缓存,那么直接获取对应的短URL进行返回,不需要再进行生成操作.

批量发号

每一次发号都需要访问一次MySQL来获取当前的最大号码,并且在获取之后更新最大号码,这个压力是比较大的.

我们可以每次从数据库获取10000个号码,然后在内存中进行发放,当剩余的号码不足1000时,重新向MySQL请求下10000个号码.在上一批号码发放完了之后,批量进行写入.

这样可以将对数据库持续的操作移到代码中进行,并且异步进行获取和写入操作,保证服务的持续高并发.

分布式

上面设计的系统是有单点的,那就是发号器是个单点,容易挂掉.

可以采用分布式服务,分布式的话,如果每一个发号器进行发号之后都需要同步给其他发号器,那未必也太麻烦了.

换一种思路,可以有两个发号器,一个发单号,一个发双号,发号之后不再是递增1,而是递增2.

类比可得,我们可以用1000个服务,分别发放0-999尾号的数字,每次发号之后递增1000.这样做很简单,服务互相之间基本都不用通信,做好自己的事情就好了.

实现

由于我懒得写JDBC代码,更懒得弄Mybatis,所以代码中使用到MySQL的地方都使用了Redis.

package util;import redis.clients.jedis.Jedis;/*** Created by pfliu on 2019/06/23.*/
public class ShortURLUtil {private static final String SHORT_URL_KEY = "SHORT_URL_KEY";private static final String LOCALHOST = "http://localhost:4444/";private static final String SHORT_LONG_PREFIX = "short_long_prefix_";private static final String CACHE_KEY_PREFIX = "cache_key_prefix_";private static final int CACHE_SECONDS = 1 * 60 * 60;private final String redisConfig;private final Jedis jedis;public ShortURLUtil(String redisConfig) {this.redisConfig = redisConfig;this.jedis = new Jedis(this.redisConfig);}public String getShortURL(String longURL, Decimal decimal) {// 查询缓存String cache = jedis.get(CACHE_KEY_PREFIX + longURL);if (cache != null) {return LOCALHOST + toOtherBaseString(Long.valueOf(cache), decimal.x);}// 自增long num = jedis.incr(SHORT_URL_KEY);// 在数据库中保存短-长URL的映射关系,可以保存在MySQL中jedis.set(SHORT_LONG_PREFIX + num, longURL);// 写入缓存jedis.setex(CACHE_KEY_PREFIX + longURL, CACHE_SECONDS, String.valueOf(num));return LOCALHOST + toOtherBaseString(num, decimal.x);}/*** 在进制表示中的字符集合*/final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L','M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};/*** 由10进制的数字转换到其他进制*/private String toOtherBaseString(long n, int base) {long num = 0;if (n < 0) {num = ((long) 2 * 0x7fffffff) + n + 2;} else {num = n;}char[] buf = new char[32];int charPos = 32;while ((num / base) > 0) {buf[--charPos] = digits[(int) (num % base)];num /= base;}buf[--charPos] = digits[(int) (num % base)];return new String(buf, charPos, (32 - charPos));}enum Decimal {D32(32),D64(64);int x;Decimal(int x) {this.x = x;}}public static void main(String[] args) {for (int i = 0; i < 100; i++) {System.out.println(new ShortURLUtil("localhost").getShortURL("www.baidudu.com", Decimal.D32));System.out.println(new ShortURLUtil("localhost").getShortURL("www.baidu.com", Decimal.D64));}}
}
热门内容:
  • 这玩意比ThreadLocal叼多了,吓得我赶紧分享出来。

  • Spring Boot 无侵入式 实现 API 接口统一 JSON 格式返回

  • MySQL大表优化方案

  • 从零搭建 Spring Cloud 服务(超级详细)

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ

阿里二面:如何设计与实现短URL服务?相关推荐

  1. 系统设计 (二)设计类似TinyURL的短URL服务

    让我们设计一个类似TinyURL的短URL服务.此服务将提供重定向到长URL的短URL别名.类似服务:bit.ly.goo.gl.qlink.me等. 1.为什么我们需要缩短URL? URL缩短用于为 ...

  2. jfinal获取url链接上面传来的string类型的值_每个公司都会用的短 URL 服务,怎么设计与实现?...

    点击上方"芋道源码",选择"设为星标" 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 8:55 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | J ...

  3. 答面试官问:如何设计短url服务

    什么是短url 短url, 顾名思义,就是将长网址缩短到一个很短的网址,用户访问这个短网址可以重定向到原本的长网址(还原).这样可以达到易于记忆.转换的目的,还有隐藏链接参数,利于短信推广的作用,常用 ...

  4. 每个公司都会用的短 URL 服务,怎么设计与实现?

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 来源:http://t.cn/AilftMhR 前言 短URL基础原理 服务设计 实现 前言 ...

  5. 短 URL 服务的设计以及实现

      背景  想必大家也经常收到垃圾短信吧--短信中的链接一般都是短链接,类似于下图这样: 为什么这里面的URL都是短的呢?有什么好处呢?怎么做到的呢? 端 URL 的好处 短信和许多平台(微博)有字数 ...

  6. 短 URL 服务,怎么设计与实现?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 呼延十 来源 | http://t.cn/Ai ...

  7. 短url服务java_Serverless-实现一个短网址服务(二)

    要点 上一篇 Serverless-实现一个短网址服务(一)实现了一个生成短链接的云函数,这一篇完成后半部分,实现短链接的跳转.主要需要注意的内容有: 腾讯云函数的API调用中如何读取path中的参数 ...

  8. 短URL服务的设计以及实现

    点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:呼延十 juejin.im/post/5d10ecab518825795a4d380 ...

  9. 短地址,短URL服务 - 百度,TinyURL

    访问百度短网址首页http://dwz.cn,输入你要缩短的原网址,生成对应的短网址.你还可以自定义你想要的短网址字符 使用百度短网址API开发的各种应用,调用百度短网址服务.例如书签.桌面程序.小插 ...

最新文章

  1. 备考12月份电子学会青少年编程能力等级测试(图形化)的公益训练营即将开营
  2. Spring+SpringMVC+Log4J
  3. 【AES图像加解密】基于AES图像加解密算法的MATLAB仿真
  4. 【03】json使用
  5. tcp协议之三次握手,四次挥手
  6. 8块钱搞定一个顶级域名 (全过程) B篇
  7. 如何在数据源是空的时候,gridview显示表头(万能)
  8. Oracle 11g行字段拼接WMSYS.WM_CONCAT问题Not A LOB
  9. Strip iPhone6
  10. 风阻能发电装置叶片的动力学仿真
  11. Java常见异常类【整理】
  12. cad2016中选择全图字体怎么操作_一键完成CAD转PDF,CAD编辑,CAD打印,无奈没人知道这波骚操作!...
  13. 腾讯三面:Cookie的SameSite了解吧,那SameParty呢?
  14. Linux基础:su命令使用方法介绍
  15. 基于WordPress搭建个人网站
  16. 闭关的日子 好无聊。偷了半日闲去书店shopping一下
  17. 关于数据库账号和密码加密问题
  18. 黑苹果驱动hd4000
  19. EFR32 资源汇总
  20. 这是你不曾见过的最全的ASO应用市场优化方式(下篇)

热门文章

  1. 【转】ASP.NET Page事件的执行顺序
  2. http status 汇总
  3. 从网站上扒网页,保存为file文件格式
  4. ARM 环境下使用azure powershell 从远程blob中拉去vhd 并创建虚拟机
  5. elasticsearch从入门到出门-01windows上安装使用
  6. 微软算法100题11 求二叉树中两节点之间的最大距离
  7. J2EE 中的服务器 tomcat6.0 配置
  8. jquery即时搜索查询插件jquery.search.js
  9. 突然想起99年的那次离别
  10. 【青少年编程】马雷越:商品价格竞猜