面试场景题系列:设计URL短链

1.场景需求界定

1.缩短URL:提供一个长URL,返回一个短很多的URL。

2.重定向URL:提供一个缩短了的URL,重定向到原URL。

3.高可用、可扩展性和容错性考量。

•写操作:每天生成1亿个URL。

•每秒的写操作数:1亿÷24÷3600≈1160。

•每秒的读操作数:假设读操作与写操作的比例是10∶1,那么每秒的读操作数是1160×10=11,600。

•假设URL缩短器会运行10年,这意味着我们必须支持1亿×365×10=3650亿条记录。

•假设URL的平均长度是100个字符,那么10年的存储容量需求是:3650亿×100字节≈36.5TB。

2.顶层设计

在这一节,我们将讨论API端点、URL重定向和URL缩短的相关流程。

2.1 API端点

API端点有利于客户端和服务器之间的通信。我们会把API设计成REST风格。如果你不熟悉REST风格的API,可以参阅一些文章,比如RestapiTutorial网站上的文章。一个URL缩短器主要需要两个API端点。

1.缩短URL。为了创建一个短URL,客户端会发送一个POST请求,它包含一个参数——原始的长URL。API看起来像下面这样:

POST api/v1/data/shorten

•请求参数:{longUrl:longURLString}。

•返回短URL。

2.重定向URL。为了把短URL重定向到对应的长URL,客户端会发送GET请求。API看起来像下面这样:

POST api/v1/shorturl

返回长URL以进行HTTP重定向。

2.2 URL重定向

图-1展示了当你在浏览器中输入一个经过缩短的TinyURL网址时会发生什么。

一旦服务器收到一个TinyURL请求,就会通过301重定向把短URL换成长URL。

客户端和服务器之间的详细通信信息如图-2所示。

图-2

**301重定向:**意味着所请求的URL“永久”移动到长URL。因为是永久重定向,所以浏览器会缓存该响应,以后对同一个URL的请求就不会发给URL缩短服务器了,而会将其直接重定向到长URL服务器。

**302重定向:**意味着URL“暂时”移动到长URL,这也意味着对于同一个URL的后续请求会先发给URL缩短服务器,然后它们才会被重定向到长URL服务器。

每种重定向方法都有自己的优缺点。如果降低服务器的负载是需要优先考虑的事项,使用301重定向就是合适的,因为对于同一个URL只有第一次请求会被发到URL缩短服务器上。但是如果数据分析很重要,那么302重定向就是更好的选择,因为它可以更轻松地跟踪点击率和点击来源。

实现URL重定向的最直观的方法就是使用哈希表。假设哈希表存储了<shortURL,longURL>键值对,可以通过以下步骤实现URL重定向。

•获取长URL:longURL=hashTable.get(shortURL)。

•一旦获取了长URL,就实施URL重定向。

2.3 缩短URL

我们假设短URL的格式为:www.tinyurl.com/{hashValue}。为了支持URL缩短的使用场景,我们必须找到一个哈希函数fx,它可以把长URL(longURL)映射成哈希值,如图-3所示。

图-3

这个哈希函数必须满足下面的要求:

•每个长URL必须可以通过哈希函数转换成一个哈希值(hashValue)。

•每个哈希值可以被映射回原始的长URL。

我们将在第3节探讨哈希函数的详细设计。

3. 设计继续深入

到目前为止,我们讨论了URL缩短和URL重定向的高层级设计。在本节中,我们会深入探讨以下内容:数据模型、哈希函数、URL缩短和URL重定向。

3.1 数据模型

在高层级设计中,所有的数据都被存储在哈希表中。这是一个很好的起点,但是在现实世界中内存资源是有限且昂贵的,因此这个方法并不可行。更好的选择是在关系型数据库中存储

图-4

3.2 哈希函数

哈希函数用于将长URL哈希成短URL,这个短URL也叫作哈希值(hashValue)。

哈希值的长度

哈希值由数字(0~9)和字母(a~z、A~Z)组成,包含62种可能的字符(10个数字+26个小写字母+26个大写字母=62)。为了确定合适的哈希值长度,我们需要找到最小的n,使得62的n次幂小于或等于3650亿。根据之前的估算,系统需要支持高达3650亿个URL。表8-1展示了随n的变化其对应支持的最大URL数量。

表-1

当n=7时,627≈3.5万亿,足够支持3650亿个URL,所以哈希值的长度应该是7位。

我们会探讨两种用于URL缩短器的哈希函数。第一种是“哈希+解决冲突”,第二种是“Base 62转换”。下面我们逐一来看一下。

为了缩短一个长URL,我们需要实现一个哈希函数将长URL哈希成7个字符的字符串。最直接的解决方案是使用那些有名的哈希函数,比如CRC32、MD5或者SHA-1等。下面的表8-2比较了对长URL“https://en.wikipedia.org/wiki/Systems_design”使用不同哈希函数的结果。

表-2

如表-2所示,即使是最短的哈希值(通过CRC32算法得到)都太长了(超过7个字符)。怎么能让它变得短一些呢?第一个方法是取哈希值的前7个字符,但是这个方法会导致哈希冲突(Hash Collision)。

为了解决哈希冲突,我们可以递归地添加一个新的预先设定好的字符串,直到不再发现冲突为止。图-5解释了这个过程。

图-5

这个方法可以消除哈希冲突,但是对每一个请求都要查询数据库以检查是否存在对应的短URL,这个成本是很高的。一种叫作布隆过滤器的技术可以提升性能。布隆过滤器是一种高效利用空间的概率性技术,可以用来检测一个元素是否属于某个集合。参考维基百科中“Bloom Filter”词条的相关介绍,可以了解更多细节。

Base 62转换

基数转换(Base Conversion)是被广泛用于URL缩短器的另一种方法。基数转换可以将同一个数字在不同的数值表示系统之间进行转换。用Base 62转换是因为一个哈希值中有62种可能的字符。下面用一个例子来解释如何进行转换:把1115710转换成Base 62的表示(1115710表示的是十进制数11,157)。

•从名字可以看出,Base 62是一种使用62个字符来进行编码的方式。其映射关系为:0→0,…,9→9,10→a,11→b,…,35→z,36→A,…,61→Z,其中“a”代表10,“Z”代表61,依此类推。

•1115710=2×622+55×621+59×620=[2,55,59],转换为Base 62的表示就是[2,T,X]。图-6展示了转换过程。•因此,短URL就是https://tinyurl.com/2TX

图-6

表-3展示了两种方法的不同点。

表-3

3.3 深入探讨URL缩短流程

作为系统的核心组成部分之一,UR L缩短流程应该是逻辑简单的,而且能提供我们想要的功能。在我们的设计里使用了Base 62转换。图-7展现了这个流程。

1.长URL是输入。

2.系统检查数据库中是否有这个长URL。

3.如果有,则意味着这个长URL此前曾经被转换为短URL。在这种情况下,从数据库中获取短URL并返回给客户端。

4.如果没有,则说明这是一个新的长URL。系统通过唯一ID生成器生成新的唯一ID(主键)。5.采用Base 62转换把这个ID转换成短URL。

6.创建一个新的数据库记录,其中包含ID、短URL和长URL。

为了更好地理解这个流程,我们来看一个具体的示例。

•假设输入的长URL是https://en.wikipedia.org/wiki/Systems_design。

•唯一ID生成器返回的ID为2009215674938。

•用Base 62转换把ID转成短URL,即ID(2009215674938)被转换成“zn9edcu”。

•将ID、短URL和长URL保存到数据库,如表-4所示。

这里,分布式唯一ID生成器值得一提。它主要的功能是生成全局唯一的ID,这个ID被用来创建短URL。在高度分布式的环境中,实现唯一ID生成器是很有挑战性的。

3.4 深入探讨URL重定向流程

图-8展示了URL重定向的详细设计。因为读操作远多于写操作,所以

图-8

URL重定向的流程总结如下:

1.用户点击一个短URL“https://tinyurl.com/zn9edcu”。

2.负载均衡器将请求转发给Web服务器。

3.如果短URL已经在缓存中,则直接返回对应的长URL。

4.如果短URL不在缓存中,则从数据库中获取对应的长URL;如果这个短URL不在数据库中,那么有可能用户输入了无效的短URL。

5.将长URL返回给用户。

4 总结

在本文中,我们讨论了API设计、数据模型、哈希函数、URL缩短和URL重定向。如果在面试的最后还有多余的时间,以下是一些可以讨论的议题。

•限流器:恶意用户发送海量的URL缩短请求是系统可能遇到的一个安全问题。限流器可以帮助我们基于IP地址或者其他过滤条件来拦截请求。如果你想回顾关于流量限制的知识,可以参考第4章。

•Web服务器伸缩:因为网络层是无状态的,所以很容易通过添加或移除Web服务器来对网络层进行伸缩。

•数据库扩展:数据库复制和分片是常用的技术。

•数据分析:对于业务而言,数据变得越来越重要。将数据分析解决方案整合到URL缩短器中可以帮助我们回答一些重要问题,比如“有多少用户点击了一个链接?”“他们是什么时候点击的?”。•可用性、一致性和可靠性。这些概念是所有大型系统成功的关键。我们在第1章中详细讨论过它们,请回顾这些内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/944464.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 基本指令

目录 1.常见指令 1.1 ls指令 1.2 pwd指令 1.3 cd指令 1.4 touch指令 1.5 mkdir指令 1.6 rm和rmdir指令 1.7 man指令 1.8 cp指令 1.9 mv指令 ​编辑 1.10 cat指令 1.11 more指令 1.12 less指令 1.13 head指令 1.14.tail指令 1.15 时间相关的指令 1.16 cal…

WEB UI 创建视图

1 视图名称 (点第1创建视图) 2 模型节点 可以空 3 上下文节点 4 新增节点下的属性 &#xff0c;参考结构(先建好的结构) 5 选择视图类型&#xff1a;&#xff08;表单&#xff0c; 列表&#xff09; 表单 &#xff1a;单条数据 列表 &#xff1a;多条数据&#xff08;表格…

redis cluster实验详解

华子目录 实验环境准备部署redis cluster添加节点删除节点redis cluster集群维护 实验 环境准备 再开3台主机 先把之前3台源码编译的redis删除 [rootredis-node1 ~]# cd /usr/local/redis/ [rootredis-node1 redis]# make uninstall[rootredis-node2 ~]# cd /usr/local/redi…

【详细讲解】hive优化

1、开启本地模式 大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过&#xff0c;有时Hive的输入数据量是非常小的。在这种情况下&#xff0c;为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况&#xff0c;Hive可…

Unity3d UGUI如何优雅的实现Web框架(Vue/Rect)类似数据绑定功能(含源码)

前言 Unity3d的UGUI系统与Web前端开发中常见的数据绑定和属性绑定机制有所不同。UGUI是一个相对简单和基础的UI系统&#xff0c;并不内置像Web前端&#xff08;例如 Vue.js或React中&#xff09;那样的双向数据绑定或自动更新UI的机制。UGUI是一种比较传统的 UI 系统&#xff…

828华为云征文|使用sysbench对Flexus X实例对mysql进行性能测评

目录 一、Flexus X实例概述 1.1?Flexus X实例 1.2?在mysql方面的优势 二、在服务器上安装MySQL 2.1 在宝塔上安装docker 2.2 使用宝塔安装mysql 2.3 准备测试数据库和数据库表 三、安装sysbench并进行性能测试 3.1 使用yum命令sysbench 3.2?运行?sysbench 并进行…

影刀进阶指令 | Kimi (对标ChatGPT)

文章目录 影刀进阶指令 | Kimi &#xff08;对标ChatGPT&#xff09;一. 需求二. 流程三. 实现3.1 流程概览3.2 流程步骤讲解1\. 确定问题2\. 填写问题并发送3\. 检测答案是否出完 四. 运维 影刀进阶指令 | Kimi &#xff08;对标ChatGPT&#xff09; 简单讲讲RPA调用kimi实现…

【教程】通过Docker运行AnythingLLM

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 官方教程&#xff1a;Local Docker Installation ~ AnythingLLM 1、先创建一个目录用于保存anythingllm的持久化文件&#xff1a; sudo mkdir /app su…

游戏引擎学习第65天

回顾我们在模拟区域更改方面的进展 目前我们正在进行游戏的架构调整&#xff0c;目标是建立一个引擎架构。我们正在实施的一个关键变化是引入模拟区域的概念&#xff0c;这样我们可以创建非常大的游戏世界&#xff0c;而这些世界的跨度不必受限于单个浮点变量。 通过这种方式…

【从零开始入门unity游戏开发之——C#篇35】C#自定义类实现Sort自定义排序

文章目录 一、List<T>自带的排序方法1、List<T>调用Sort()排序2、 能够使用 Sort() 方法进行排序的本质 二、自定义类的排序1、通过实现泛型IComparable<T> 接口&#xff08;1&#xff09;示例&#xff08;2&#xff09;直接调用 int 类型的 CompareTo 方法进…

YOLO系列正传(五)YOLOv4论文精解(上):从CSPNet、SPP、PANet到CSPDarknet-53

系列文章 YOLO系列基础 YOLO系列基础合集——小白也看得懂的论文精解-CSDN博客 YOLO系列正传 YOLO系列正传&#xff08;一&#xff09;类别损失与MSE损失函数、交叉熵损失函数-CSDN博客 YOLO系列正传&#xff08;二&#xff09;YOLOv3论文精解(上)——从FPN到darknet-53-C…

Redis 实战篇 ——《黑马点评》(上)

《引言》 在进行了前面关于 Redis 基础篇及其客户端的学习之后&#xff0c;开始着手进行实战篇的学习。因内容很多&#xff0c;所以将会分为【 上 中 下 】三篇记录学习的内容与在学习的过程中解决问题的方法。Redis 实战篇的内容我写的很详细&#xff0c;为了能写的更好也付出…

DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(2)

DevOps实战&#xff1a;用Kubernetes和Argo打造自动化CI/CD流程&#xff08;2&#xff09; 背景 Tips 翻遍国内外的文档&#xff0c;关于 Argo 作为 CI/CD 当前所有开源的文档&#xff0c;博客&#xff0c;argo官方文档。得出的结论是&#xff1a; argo官方给出的例子都相对…

探索Flink动态CEP:杭州银行的实战案例

摘要&#xff1a;本文撰写自杭州银行大数据工程师唐占峰、欧阳武林老师。将介绍 Flink 动态 CEP的定义与核心概念、应用场景、并深入探讨其技术实现并介绍使用方式。主要分为以下几个内容&#xff1a; Flink动态CEP简介 Flink动态CEP的应用场景 Flink动态CEP的技术实现 Flin…

STM32F103RCT6学习之三:串口

1.串口基础 2.串口发送 1&#xff09;基本配置 注意&#xff1a;实现串口通信功能需在keil中设置打开Use Micro LIB&#xff0c;才能通过串口助手观察到串口信息 2)编辑代码 int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration-------------…

Python中构建终端应用界面利器——Blessed模块

在现代开发中&#xff0c;命令行应用已经不再仅仅是一个简单的文本输入输出工具。随着需求的复杂化和用户体验的重视&#xff0c;终端界面也逐渐成为一个不可忽视的设计环节。 如果你曾经尝试过开发终端UI&#xff0c;可能对传统的 print() 或者 input() 函数感到不满足&#…

OpenHarmony-5.PM 子系统(2)

电池服务组件OpenHarmony-4.1-Release 1.电池服务组件 Battery Manager 提供了电池信息查询的接口&#xff0c;同时开发者也可以通过公共事件监听电池状态和充放电状态的变化。电池服务组件提供如下功能&#xff1a; 电池信息查询。充放电状态查询。关机充电。 电池服务组件架…

Java 网络原理 ①-IO多路复用 || 自定义协议 || XML || JSON

这里是Themberfue 在学习完简单的网络编程后&#xff0c;我们将更加深入网络的学习——HTTP协议、TCP协议、UDP协议、IP协议........... IO多路复用 ✨在上一节基于 TCP 协议 编写应用层代码时&#xff0c;我们通过一个线程处理连接的申请&#xff0c;随后通过多线程或者线程…

基于规则的系统架构:理论与实践

在当今信息化快速发展的时代&#xff0c;企业面临着日益复杂和多变的市场环境&#xff0c;传统的静态系统架构已难以满足快速响应业务变化的需求。基于规则的系统架构&#xff08;Rule-Based System Architecture, RBSA&#xff09;作为一种灵活、可扩展的架构模式&#xff0c;…

记一个itertools排列组合和列表随机排序的例子

朋友不知道哪里弄来了一长串单词列表&#xff0c;一定要搞个单词不重复的组合。那么这个时候我们就可以想到读书时所学的排列组合知识了&#xff0c;而这个在Python中可以怎么实现呢&#xff1f;我记录如下&#xff1a; 使用itertools模块实现排列组合 在 Python 中&#xff…