程序员冈刀,目前就职于美团,java开发工程师,研究生。2022年,毕业于北京邮电大学电子工程学院、电子与通信工程专业。个人公众号《代码废柴》欢迎关注。
1. 简介
实现URL缩短服务并不是一项复杂的任务,它通常是系统设计面试的一部分。在这篇文章中,我将尝试解释实现该服务的过程。URL缩短器是一种用于从非常长的URL创建短链接的服务。通常,短链接的大小是原始URL的三分之一甚至四分之一,这使得它们更容易打字、展示或发布。点击短链接用户将自动重定向到原始URL。目前,网上有很多网址缩短服务,比如tiny.cc、bitly.com、cutt.ly 等等。
2. URL缩短器的需求
在实现之前,用功能性和非功能性需求的形式写下需要完成的工作。
功能需求:
- 用户需要能够输入一个较长的URL。我们的服务应该保存该URL并生成一个短链接。
- 点击短链接会将用户重定向到原来的长URL。
- 用户应该可以选择输入过期日期。过了这个日期,短链接就无效了。
- 用户需要创建一个帐户才能使用该服务。服务可以有每个用户的使用限制(可选)
- 允许用户创建自己的短链接*-服务应该有指标,例如,访问次数最多的链接(可选)
非功能需求:
- 服务应该在100%的时间内启动并运行,也就是稳定性可靠的。
- 重定向的持续时间不能超过两秒
3. URL缩短器核心算法
假设我们想要一个最大长度为7的短链接。URL缩短器中最重要的是转换算法。URL转换可以通过几种不同的方式实现,每种方式都有其优缺点。这里列举出比较常用的3种实现方式。
方法一: 生成短链接的一种方法是使用一些哈希函数(例如MD5或SHA-2)对原始URL进行哈希。当使用哈希函数时,不同的输入肯定会导致不同的输出。哈希的结果大于7个字符,所以我们需要取前7个字符。但是,在这种情况下,可能会发生冲突,因为前七个字符可能已经被用作短链接。比较简单的解决方式是可以选取取接下来的七个字符,直到我们找到一个没有使用的短链接。
方法二: 生成短链接的第二种方法是使用uuid。UUID被复制的概率不是零,但它非常接近于零,可以忽略不计。由于UUID有36个字符,这意味着我们会遇到与上面相同的问题。我们应该使用前七个字符并检查该组合是否已经在使用。
方法三: 将数字从10进制转换为62进制。基数是一组数字或字符,可以用来表示一个特定的数字。以10为底是我们日常生活中使用的数字[0-9],以62为底是[0-9][a-z][A-Z]。这意味着,例如,一个以10为底的四位数的数字与以62为底的数字相同,但有两个字符。
在URL转换中使用62进制,最大长度为7个字符,可以让我们在短链接中拥有62^7个唯一值。
4. 62进制转换实现如何实现?
我们有一个以10为底的数,我们想把它转换成62为底。我们将使用以下算法:
public class Base62Convert {
public static final char[] map2Char =
{'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'
};
public static String convert64Value(long number) {
StringBuilder sb = new StringBuilder();
while (number > 0) {
sb.append(map2Char[((int) (number % 62))]);
number = number / 62;
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(convert64Value(2283281389712938712L));
}
}
5. 实现的核心过程
首先,需要有一个全局的ID生成器,这里可以使用Redis或者其他的技术实现。ID生成器的规则是可以生成0~62^7之间的数字。这个数据量大约是3千亿。然后根据生成好的ID放入到上面的算法中,得到具体短的 URL token。 当用户在此请求的时候,可以使用短的URL进行直接的跳转到长的URL上面。这样就实现了一个简易的URL缩短器。
6. 其他的关键性问题
实现一个URL缩短器,只要有比较好的算法,很容易就可以得到比较优秀的应用。本文的62进制仅仅是列举一个例子,实际上也可以实现更多的进制,再加上特殊的符号。除此之外,还需要考虑并发量以及系统的可用性的问题,这才是关注的重点。在这里,可以将URL生成器和转换器分开部署到不同的服务。而且,在查询的过程中,也一定关注服务的请求耗时,防止出现服务雪崩的发生。
程序员冈刀,目前就职于美团,java开发工程师,研究生。2022年,毕业于北京邮电大学电子工程学院、电子与通信工程专业。个人公众号《代码废柴》欢迎关注。