当前位置:   article > 正文

短链接设计和思考_如何通过分布式id生成器生成短链接id

如何通过分布式id生成器生成短链接id

目录

什么是长链接、什么是短链接?

有了长链接为啥需要短链接呢?

短链接如何跳转到长链接?

长链接如何生成短连接?

1 哈希算法生成短连接

2 ID生成器生成短链接

10进制和62进制转换代码


什么是长链接、什么是短链接?

https://github.com/jack1liu/Java/ 这个地址一共33个字符,属于长链接。当然这个只是示例,真实场景会带有各种参数。

http://d.sb.com/U7eRz 这个地址是上面的长链接地址经过处理得到的,一共21个字符,属于短链接。

有了长链接为啥需要短链接呢?

以发送营销短信为例子,每一条短信字符是有上限的。

  • 如果使用长链接很容易超过单条短信上限,将变成两条短信,成本增加,用户体验也很差。
  • 如果使用短链接,将大大减少字符数目,由于链接字符的变少,文字部分可以变多。

当然了,短链接除了经常使用在营销短信场景,还被广泛应用于生成二维码

短链接如何跳转到长链接?

假设用户收到营销短信,之后点击营销短信里面的短链接,是如何跳转到长链接的呢?

主要为三步:

一 客户端访问短链接地址,短链接服务器校验是否是自己颁发的地址。

二 短链接服务器识别出是自己颁发的地址,302重定向到长链接地址。

三 客户端获取到长链接地址进行访问。

长链接如何生成短连接?

1 哈希算法生成短连接

哈希算法可以将一个不管多长的字符串,转化成一个长度固定的哈希值。

其中比较著名并且应用广泛的一个哈希算法,那就是 MurmurHash 算法。该算法计算速度快和冲突概率小。

GitHub - jack1liu/Java: Java技术栈学习记录 通过 32bits MurmurHash 算法得到哈希值 445113871。

将哈希值拼接域名很容易得到,短网址:http://d.sb.com/445113871

由于 Google 的 guava 包有 MurmurHash 算法的实现。这块附上 guava 的依赖。

  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>19.0</version>
  5. </dependency>

能不能让短网址更短呢?

可以的,445113871 是十进制表示,我们可以选择更高进制表示。业内用的最多的是62进制。

为什么要用62进制?64进制不行么?

62进制只含数字+小写字母+大写字母;64进制会含有"/,+"这样的符号,不符合正常URL的字符。而且如果是6位62进制的话,能有560亿种组合,满足业务需求。

我们都知道在使用哈希算法的时候有可能会出现冲突。所谓的冲突就是不同的长链接地址哈希会生成相同的短链接。用户通过短链接不知道访问哪个长链接。

如何解决哈希冲突问题呢?

用 MySQL 保存短链接和长链接的映射关系,短链接字段加上唯一索引。

一 当有一个新长链接需要生成短链接的时候,通过 MurmurHash 算法,62进制转换,生成短链接。

二 在映射表中通过短链接查询,如果没有找到短链接,将短链接和长链接映射关系写入表中。

三 如果映射表有记录,将映射表中得到的长链接和新长链接进行对比,如果相同。直接使用短链接。

四 如果映射表得到的长链接和新长链接不同,出现了哈希冲突。这个时候我们可以给新长链接拼接特定字符再进行哈希。

五 这个特定字符可以自定义,比如[short_url],需要注意的是数据库写入的加上特定字符的,给客户端返回的时候需要去掉特定字符。

2 ID生成器生成短链接

我们维护一个 ID 自增生成器。它可以生成 1、2、3…这样自增的整数 ID。

分布式 id_新猿一马的博客-CSDN博客目录一 为什么需要分布式 ID二 如何生成分布式 ID2.1 数据库自增 ID2.2 UUID 生成2.3 本地时间2.4snowflake 算法2.5 snowflake 算法优化三 参考文档一 为什么需要分布式 ID 一个唯一 ID 在一个分布式系统中是非常重要的一个业务属性,其中包括一些如订单 ID,消息 ID ,会话 ID,他们都有一些...https://blog.csdn.net/jack1liu/article/details/95887201一 当短链接服务接收到一个长链接转成短链接请求之后,它先从 ID 生成器中取一个 id。

二 将 id 转化成 62 进制,将得到的结果拼接到短链接域名后面,得到最终的短链接。

三 将生成的短链接和对应的长链接存储到数据库中。

这块有一个问题,假设相同的长链接两次来生成短链接,这块会生成两个不同的短链接。

从用户的角度来看,是不影响用户使用的,因为不管是哪个短链接,最终都是一个长链接。

从存储的角度来看,如果请求N次,这块的数据存储压力是很大的,而且很多都是脏数据。需要添加唯一索引。

10进制和62进制转换代码

  1. package com.sb.shorturl.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. public class ConversionUtils {
  4. /**
  5. * 初始化 62 进制数据,索引位置代表字符的数值,比如 A代表10,z代表61等
  6. */
  7. private static String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  8. private static int scale = 62;
  9. /**
  10. * 将数字转为62进制
  11. *
  12. * @param num Long 型数字
  13. * @param length 转换后的字符串长度,不足则左侧补0
  14. * @return 62进制字符串
  15. */
  16. public static String encode(long num, int length) {
  17. StringBuilder sb = new StringBuilder();
  18. int remainder = 0;
  19. while (num > scale - 1) {
  20. /**
  21. * 对 scale 进行求余,然后将余数追加至 sb 中,由于是从末位开始追加的,因此最后需要反转(reverse)字符串
  22. */
  23. remainder = Long.valueOf(num % scale).intValue();
  24. sb.append(chars.charAt(remainder));
  25. num = num / scale;
  26. }
  27. sb.append(chars.charAt(Long.valueOf(num).intValue()));
  28. String value = sb.reverse().toString();
  29. return StringUtils.leftPad(value, length, '0');
  30. }
  31. /**
  32. * 62进制字符串转为数字
  33. *
  34. * @param str 编码后的62进制字符串
  35. * @return 解码后的 10 进制字符串
  36. */
  37. public static long decode(String str) {
  38. /**
  39. * 将 0 开头的字符串进行替换
  40. */
  41. str = str.replace("^0*", "");
  42. long num = 0;
  43. int index = 0;
  44. for (int i = 0; i < str.length(); i++) {
  45. /**
  46. * 查找字符的索引位置
  47. */
  48. index = chars.indexOf(str.charAt(i));
  49. /**
  50. * 索引位置代表字符的数值
  51. */
  52. num += (long) (index * (Math.pow(scale, str.length() - i - 1)));
  53. }
  54. return num;
  55. }
  56. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/446353
推荐阅读
相关标签
  

闽ICP备14008679号