在本章中,我们将解决一个有趣而经典的系统设计面试问题:设计一个像tinyurl这样的URL缩短服务。
第一步-理解问题并且设计范围
系统设计面试的问题是故意留下开放式的。为了设计一个精心设计的系统,提出澄清性问题是至关重要的。 候选人:你能举例说明网址缩短器是如何工作的吗?采访者:假设网址www.systeminterview.com/q=chatsyste… y7keocwj。如果您单击别名,它会将您重定向到原始URL。
候选人:请求流量是多少?面试官:每天产生1亿个url。
候选人:缩短后的URL有多长?面试官:越短越好。
候选人:缩短后的URL中允许使用哪些字符?面试官:缩短的URL可以是数字(0-9)和字符(a-z, AZ)的组合。
候选人:短网址可以删除或更新吗? 面试官:为了简单起见,让我们假设缩短的url不能被删除或更新。 以下是基本用例:
- URL缩短:给定一个长URL =>返回一个更短的URL 。
- URL重定向:给定较短的URL =>重定向到原始URL。
- 高可用性、可伸缩性和容错考虑。
数据的背景估计
-
写操作:每天生成1亿个url。
-
每秒写操作:1亿/ 24 /3600 = 1160
-
读操作:假设读操作与写操作的比例为10:1,每秒读操作:1160 * 10 = 11,600
-
假设URL缩短服务运行10年,这意味着我们必须支持1亿* 365 * 10 = 3650亿条记录。
-
假设平均URL长度为100。
-
10年以上存储需求:3650亿* 100字节* 10年= 365tb。
对你来说,和面试官讨论这些假设和计算是很重要的,这样你们就能达成一致。
步骤二-提出顶层设计并且获得支持
在本节中,我们将讨论API端、URL重定向和URL缩短。
API Endpoints
API Endpoints促进了客户机和服务器之间的通信。我们将设计rest风格的api。如果不熟悉restful API,可以参考外部资料,如参考资料[1]。URL缩短器主要需要两个API端点。
1.网址缩短。为了创建一个新的短URL,客户端发送一个POST请求,该请求包含一个参数:原始的长URL。API是这样的: POST api/v1/data/shorten
- 请求参数:{longUrl: longURLString}
- 返回shortURLURL重定向。
2.为了将短URL重定向到相应的长URL,客户端发送GET请求。
- API看起来是这样的:GET API /v1/shortUrl
- 返回HTTP重定向的longURL
URL重定向
如图8-1所示,在浏览器中输入一个tinyurl。一旦服务器接收到一个tinyurl请求,它就用301重定向将短URL更改为长URL。
客户端和服务器之间的详细通信如图8-2所示。
这里值得讨论的一件事是301重定向和302重定向。
301重定向。301重定向显示所请求的URL被“永久”移动到长URL。由于它是永久重定向的,浏览器缓存响应,并且对同一URL的后续请求将不会发送到URL缩短服务。相反,请求被直接重定向到长URL服务器。
302重定向。302重定向意味着URL被“暂时”移动到长URL,这意味着对同一URL的后续请求将首先发送到URL缩短服务。然后,它们被重定向到长URL服务器。
每种重定向方法都有其优点和缺点。如果优先级是减少服务器负载,使用301重定向是有意义的,因为只有相同URL的第一个请求被发送到URL缩短服务器。然而,如果分析很重要,302重定向是一个更好的选择,因为它可以更容易地跟踪点击率和点击来源。
实现URL重定向最直观的方法是使用哈希表。假设哈希表存储对,URL重定向可以通过以下方式实现:
- 获取longURL: longURL = hashTable.get(shortURL)
- 一旦您获得了longURL,执行URL重定向
URL缩短
让我们假设短URL是这样的:www.tinyurl.com/{hashValue}…
哈希函数必须满足以下要求:
-
每个longURL必须被哈希到一个hashValue。
-
每个hashValue都可以映射回longURL。
对哈希函数的详细设计进行了深入的讨论。
第三步-底层设计
到目前为止,我们已经讨论了URL缩短和URL重定向的高级设计。在本节中,我们将深入探讨以下内容:数据模型、哈希函数、URL缩短和URL重定向。
数据模型
在高级设计中,所有内容都存储在散列表中。这是一个很好的起点;然而,这种方法对于实际系统是不可行的,因为内存资源是有限和昂贵的。更好的选择是在关系数据库中存储映射。图8-4展示了一个简单的数据库表设计。表的简化版本包含3列:id、shortURL、longURL。
Hash函数
哈希函数用于将长URL哈希为短URL,也称为hashValue。
Hash值的长度
hashValue由字符[0-9,a-z, a-z]组成,包含10 + 26 + 26 = 62个字符。求hashValue的长度,求最小的n,使62^n≥3650亿。根据信封背面的估计,系统必须支持最多3650亿个url。表8-1显示了hashValue的长度和对应的最大url数。
当n = 7,62 ^ n = ~3.5万亿时,3.5万亿足以容纳3650亿个url,因此hashValue的长度为7。
我们将探索URL缩短器的两种类型的哈希函数。第一个是“哈希+碰撞解析”,第二个是“62进制转换”。让我们一个一个来看。
Hash碰撞解决办法
为了缩短长URL,我们应该实现一个散列函数,将长URL散列到一个7个字符的字符串。一个直接的解决方案是使用众所周知的散列函数,如CRC32、MD5或SHA-1。下表比较了对该URL应用不同哈希函数后的哈希结果:en.wikipedia.org/wiki/System…
如表8-2所示,即使是最短的哈希值(来自CRC32)也太长(超过7个字符)。我们怎样才能缩短它?第一种方法是收集哈希值的前7个字符;然而,这种方法可能导致哈希冲突。为了解决哈希冲突,我们可以递归地附加一个新的预定义字符串,直到没有发现冲突。图8-5解释了这个过程。
这种方法可以消除碰撞;但是,查询数据库以检查每个请求是否存在shortURL的成本很高。一种叫做布隆过滤器的技术可以提高性能。布隆过滤器是一种空间效率高的概率技术,用于测试元素是否为集合的成员。详见参考资料。
62进制转换
基转换是URL缩短器常用的另一种方法。基数转换有助于在不同的数字表示系统之间转换相同的数字。使用Base 62转换,因为hashValue有62个可能的字符。让我们使用一个示例来解释转换是如何工作的:将1115710转换为以62为基数的表示(1115710在以10为基数的系统中表示11157)。
-
从它的名字可以看出,base 62是一种使用62个字符进行编码的方法。映射为:0-0,…, 9- 9,10 -a, 11-b,…, 35-z, 36-A,…例如,61-Z,其中“a”代表10,“Z”代表61,等等。
-
1115710 = 2 × 62^2 + 55 × 62^1 + 59 × 62^0 = [2, 55, 59] -> [2, T, x],以62进制表示。对话过程如图8-6所示。
- Thus, the short URL is tinyurl.com /2TX
两种方法的比较
两种方法的区别如表8-3所示。
网址缩短深度设计
作为系统的核心部分之一,我们希望URL缩短流在逻辑上简单且功能齐全。在我们的设计中使用了Base 62转换。我们构建下面的图(图8-7)来演示这个流程。
-
longURL是输入。
-
系统检查longURL是否在数据库中。
-
如果是,则表示之前将长url转换为短url。在本例中,从数据库中获取shortURL并将其返回给客户端。
-
如果不是,则longURL是新的。新的唯一ID(主键)由唯一ID生成器生成。
-
使用base 62转换将ID转换为shortURL。
-
用ID、shortURL和longURL创建一个新的数据库行。
为了使流程更容易理解,让我们看一个具体的例子。
-
假设输入的longURL为:en.wikipedia.org/wiki/System…: 2009215674938。
-
使用base 62转换ID为shortURL。ID(2009215674938)转换为“zn9edcu”。
-
将ID、shortURL和longURL保存到数据库中,如表8-4所示。
分布式唯一ID生成器值得一提。它的主要功能是生成全局唯一的id,用于创建短url。在高度分布式的环境中,实现唯一ID生成器是具有挑战性的。幸运的是,我们已经在“第7章:在分布式系统中设计唯一ID生成器”中讨论了一些解决方案。你可以回过头来复习一下。
URL重定向
URL重定向的详细设计如图8-8所示。由于读操作多于写操作,因此将映射存储在缓存中以提高性能。
URL重定向的流程总结如下: 1.重定向。 1.用户单击URL短链接tinyurl.com/zn9edcu。负载均…
-
如果短url已经在缓存中,则直接返回长url。
-
如果短url不在缓存中,则从数据库中获取长url。如果不在数据库中,则可能是用户输入了无效的shortURL。
-
longURL返回给用户。
第四步-打包
在本章中,我们讨论了API设计、数据模型、哈希函数、URL缩短和URL重定向。
如果在面试结束时有额外的时间,这里有一些额外的谈话要点。
速率限制:我们可能面临的一个潜在安全问题是,恶意用户会发送大量的URL缩短请求。速率限制可以根据IP地址或其他过滤规则对请求进行过滤。如果你想刷新关于速率限制的记忆,请参考“第4章:设计速率限制器”。
-
Web服务器扩展:由于Web层是无状态的,所以通过添加或删除Web服务器来扩展Web层很容易。
-
数据库扩展:数据库复制和分片是常用的技术。
-
分析:数据对商业成功越来越重要。将分析解决方案集成到URL缩短器中可以帮助回答一些重要的问题,比如有多少人点击了链接?他们什么时候点击链接?等。
-
可用性、一致性和可靠性。这些概念是任何大型系统成功的核心。我们在第1章中详细讨论了它们,请复习一下这些主题。
恭喜你走了这么远!现在给自己点鼓励吧。好工作!