简历上写这个短地址服务,面试直接通过了!

一、背景

为什么要使用短地址服务,具体使用的业务场景如下:

  1. 营销短信有字数限制,链接太长会影响短信内容的条数(涉及到费用问题)。
  2. 相对于长链接,短链接更安全,不暴露访问参数。
  3. 方便短链接进行统计。例如点击量,访问用户使用设备等。
  4. 短链接更简洁,不像长链接有一大堆参数。

二、技术方案与实现

2.1.实现原理

  1. 短地址服务将使用的长链接转成成短链接;
  2. 把短链接通过短信发送出去;
  3. 用户在收到短链接后,点击短链接跳转到短地址服务系统上;
  4. 短地址服务根据短链接获取与其对应的长链接地址后采用 301 或 302 进行重定向到长地址;

短地址项目核心就是将长链接转换成短链接,并保证每个长链接对应唯一的短链接。如果出现一个短链接对应2个长链接的话,将不能确定重定向的地址。

2.2.长链接转成短链接策略方法

2.21 算法策略

通过算法将长链接和短链接进行互转,这种方式的缺点是:会产生重复的链接,假设使用算法,那么算法的性能也不高。

2.2.2 算法+存储

通过算法将长链接转成短链接并将长链接和短链接关系存入数据库。这个方式绕开了短链接转换成长链接,但是没有解决长链接转成短链接重复的问题。

2.2.3 Hash 算法

使用 Hash 算法,Hash 碰撞后再对重复的进行标记区分。Hash算法中有一个相对比较可行的方法是:摘要算法。摘要算法,生成短码是固定4个,但是仍然存在重复几率。

摘要算法算法过程:

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

2.2.4 随机数策略

通过生成一个随机数来表示一个短地址,然后查询数据库是否用过,用过就再随机,如此往复。缺点:生成性能太差,短链接和长链接信息越多,循环处理是否重复的次数就越大。

2.2.5 发号策略

又叫自增序列算法或永不重复算法,通过设置一个初始的 Long 数值,每生成一个短链接将这个数值 +1 。数值与长链接一一对应,然后通过 base 62 将数字转换成相对比较短的短码(低进制转化为高进制时,字符数会减少的特性)

2.3 各种算法是否可行分析

算法策略、算法+存储、随机数策略、hash 算法 都会产生重复的数据,也就是一个短码对应多个长链接。只有自增序列算法不会出现重复。但是也有采用摘要算法来实现,这种方式虽然会产生重复的短码,但是概率非常低。综合分析我们短地址服务采用自增序列算法来实现。

2.4 自增序列算法存在问题与解决方案

2.4.1 短码超用

问题描述:因为采用的数值递增的方式,假设使用Long 值表示:long 最大值 9223372036854775807L == 2 的 63 次方 -1。理论上讲肯定会超。

解决方案:短码超用的问题,首先是自增号 long 最大值 9223372036854775807L == 2 63次方 -1,假设我们短码用 6 位表示:就会产生约 62 的 6 次方约等于 568 亿,这么大的数量量基本不会用超。就算6位用完可以用7 位 、8位。

2.4.2 短码是有序不安全

问题描述:自增序列算法其实是通过数值自增然后 base62,当然也可以通过 base62 进行还原。别人可以通过穷举你的短链地址的获取到真的长链接信息。对于使用者来说有点不安全。

解决方案:短码是有序不安全问题:我们采用的是 Hashids(https://hashids.org/java/) 可以添加秘钥生成唯一id,防止信息泄露。,该工具类是在 base62 添加了秘钥,只要秘钥不泄露,被还原的难度还是比较大的。

2.4.3 活动秒杀链接高频访问性能问题

问题描述:有的短链接可能是活动推过、秒杀页面等,这个链接会被高频访问。如果不处理性能瓶颈将会卡在短链接服务上。

解决方案:活动秒杀链接高频访问性能问题:对于可能被高频访问短链接,通过增加缓存来提高自增号对应长链接的查找速度。查询走缓存大大降低数据库的压力。

缓存 kv 形式: 自增号 -> 长链接 或 短码 -> 长链接。Redis 缓存并采用LRU 算法淘汰经常不访问的长链接或短码。并通过2级别缓存,提高缓存的高可用。

2.4.4 如何保证短链接服务高可用(分布式)

问题描述:通过集群方式部署解决单点出现不可用的问题,但是有个核心的问题就是,如果保证集群下产生的短码不重复。暂未处理。目前采用是单点

解决方案:每个实例处理不同的号段 4个实例 分别处理 1 2 3 4 下次在生成则每个实例递增 4。这种方式优点是每个实例处理各自的号短。或 通过分布式锁避免重复递增的问题。存在一定的性能问题。

2.4.5 预防攻击问题

问题描述:大量攻击请求生成短链接消耗我们的号段。攻击的形式有2中:大量相同的长链接生成短链接请求、和大量不同的长链接生成短链接的请求。

解决方案:大量相同的长链接生成短链接请求:缓存长链接和自增号,当大量同一个长链接过来,直接从缓存服务器里返回短网址,这样就无法耗光我们的自增号了。

大量不同的长链接生成短链接的请求:系统可以自己统计 ip 访问量进行限制,也可以采用网关或nginx 进行限流处理。

2.5.短地址服务其他问题与解决方案

2.5.1 是否分库分表

实现采用递增号池取号处理逻辑,并且事务偏弱。故采用MongoDB 。

2.5.2 重定向 301 or 302

301 是永久重定向,第一次访问短链接会通过短地址服务跳转到长链接后,游览器会将其缓存。再次访问短地址则会不经过短链接服务器直接跳转长链接地址。

301 对搜索引擎更友好,同时对服务器压力也会有一定减少。大部分短地址服务采用的是 301。

302 是临时重定向。每次访问都会走短地址服务,不过好处是可以统计访问次数,访问设备等信息进行分析。缺点是会增加服务器的压力。

解决方案:默认使用 301 ,可以通生成参数定义 302 重定向的短链接。

小结

小奎参与设计的短地址服务,使用发号策略进行实现,通过 Hashids 解决短码有序不安全问题。同时通过缓存保证服务高可用以及通过 用MongoDB 解决数据量的问题。

如果你有任何关于短地址服务疑问,欢迎在评论区留言分享,我们一起交流学习,共同进步!下期技术分享,我们不见不散!

在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-07 17:08:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-07 17:08:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-07 17:08:01       87 阅读
  4. Python语言-面向对象

    2024-04-07 17:08:01       96 阅读

热门阅读

  1. MySQL-相关数据类型

    2024-04-07 17:08:01       35 阅读
  2. ASA防火墙

    2024-04-07 17:08:01       31 阅读
  3. css:img引入svg后修改颜色

    2024-04-07 17:08:01       35 阅读
  4. 卸载Mysql方法

    2024-04-07 17:08:01       39 阅读
  5. linux中脚本化控制screen

    2024-04-07 17:08:01       37 阅读
  6. MySQL基础学习内容指南

    2024-04-07 17:08:01       28 阅读
  7. 设计模式:组合模式

    2024-04-07 17:08:01       41 阅读
  8. 【DevOps工具篇】身份验证管理及SSO登录:Keycloak

    2024-04-07 17:08:01       33 阅读