系统设计面试题 之 如何设计Pastebin.com

2024-03-19 02:32

本文主要是介绍系统设计面试题 之 如何设计Pastebin.com,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文链接:https://github.com/donnemartin/system-design-primer/blob/master/solutions/system_design/pastebin/README.md

第一步:搜集用例和约束
在面试过程中,我们需要向面试官询问需求以设计用例,但是在本文中我们自己设计用例因为没有面试官。

1.用例
本文只解决以下用例:

1)用户输入一个文本块,获得一个随机生成的链接;
过期:
a.默认设置是不过期(译者注:但这样数据库会越来越大,所以我觉得应该有一个默认的过期时间)
b.能够可选的设置一个过期时间
2)用户输入一个粘贴板url,就能查看对应的内容
3)用户可以是匿名的
4)我们需要有一个服务来跟踪页面的使用状况
5)我们需要有一个服务来删除过期的粘贴板
6)我们的服务要有高可靠性

本文不解决以下用例:
1)用户注册一个账号以及邮箱确认
2)用户登入一个注册账号以及修改粘贴板
3)用户能设置可见性
4)用户能设置短链接

2.约束和假设
状态假设:

1)流量是不均匀分布的
2)Following a short link should be fast(译者注:没看明白啥意思)
3)只能粘帖纯文本
4)页面使用状况的分析不需要实时
5)1000万用户
6)每个月有1000万用户写操作
7)每个月有1亿用户读操作
8)读写比率是10:1

计算使用率
如果你被要求估计使用率的话,请和面试官先讨论。

1)每个剪贴板的size
a.每个剪贴板1kb的size
b.shortlink - 7字节
c.一分钟为单位的过期时间 - 4字节
d.创建时间 - 5字节
e.粘贴板路径 - 255字节
f.总计 =~ 1.27kb
2)每个月新增12.7GB的粘贴板内容
a.每个粘贴板1.27kb的size乘以每个月1000万用户
b.3年内需要大约450GB空间
c.3年内3600万短链接
d.假设大部分粘贴板都是新建的,而不是对旧粘贴板的修改
3)平均每秒4个写操作
4)平均每秒40个读操作

一些方便计算的提示:
1)每个月有250万秒
2)每秒1个请求 = 每个月250万个请求
3)每秒40个请求 = 每个月1亿个请求
4)每秒400个请求 = 每个月10亿个请求

第二步:本文的顶层设计如下图

第三步:设计核心组件

1. 用户输入一个文本块,获得一个随机生成的链接
我们可以把关系数据库当作一个巨大的哈希表来使用,这个哈希表可以把生成的url映射到文件服务器以及粘贴板文件的路径上。
相对于使用文件服务器,我们也可以使用例如Amazon S3或者NoSql document之类的面向对象存储。
另外,我们也可以使用NoSql key-value来取代关系数据库作为哈希表的方法。以下讨论基于关系数据的方法:
1)客户发送一个创建粘贴板的请求给web服务器,该web服务器实际上是一个反向代理
2)web服务器把请求转发给Write API服务器;
3)Write API服务器做以下操作:
a.通过查询sql数据库检查url是否唯一
b.如果url不唯一,就会生成另一个url
c.如果我们支持自定义url的话,那么我们可以使用用户提供的url
4)保存数据到sql数据库的pastes表
5)保存粘贴板数据到面向对象存储
6)返回url
pastes表如下:

shortlink char(7) NOT NULL
expiration_length_in_minutes int NOT NULL
created_at datetime NOT NULL
paste_path varchar(255) NOT NULL
PRIMARY KEY(shortlink)

我们将会为shortlink和created_at创建索引以加速查询(log-time instead of scanning the entire table)(译者注:没看明白这句话)并且把数据保存在内存中。
为了生成唯一的url,我们可以:
1)使用md5算法对用户ip和时间戳计算hash:
md5是一个使用广泛地128位哈希算法。md5均匀分布。我们可以用md5算法生成随机url。
2)使用base62编码hash
base62对哈希值的编码是确定唯一的。base62使用[a-zA-Z0-9]编码适用于url;base64多了两个字符+和/,所以不适用于url生成。以下是base62伪码:

def base_encode(num, base=62):digits = []while num > 0remainder = modulo(num, base)digits.push(remainder)num = divide(num, base)digits = digits.reverse

3)我们只取输出结果的前7个字符,这样就有62^{^{7}}种可能的值;应该足够处理我们三年中的3.6亿个短链接:

url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH]

我们还需要一个公有的REST API:

$ curl -X POST --data '{ "expiration_length_in_minutes": "60", \"paste_contents": "Hello World!" }' https://pastebin.com/api/v1/paste

返回结果:

{"shortlink": "foobar"
}

2.用户输入一个粘贴板url,就能查看对应的内容

1)用户发送一个获取粘贴板的请求给web服务器;
2)web服务器转发请求给Read API服务器;
3)Read API服务器做以下操作:
检查sql数据库是否存在对应于url的数据。如果url已经存在于数据库中的话,就从面向对象存储中获取粘贴板的内容;否则的话,返回错误。
REST API:

$ curl https://pastebin.com/api/v1/paste?shortlink=foobar

响应值:

{"paste_contents": "Hello World""created_at": "YYYY-MM-DD HH:MM:SS""expiration_length_in_minutes": "60"
}

3.我们需要有一个服务来跟踪页面的使用状况由于我们不需要实时分析页面使用情况,所以我们可以简单地使用mapreduce来分析页面使用情况。

class HitCounts(MRJob):def extract_url(self, line):"""Extract the generated url from the log line."""...def extract_year_month(self, line):"""Return the year and month portions of the timestamp."""...def mapper(self, _, line):"""Parse each log line, extract and transform relevant lines.Emit key value pairs of the form:(2016-01, url0), 1(2016-01, url0), 1(2016-01, url1), 1"""url = self.extract_url(line)period = self.extract_year_month(line)yield (period, url), 1def reducer(self, key, values):"""Sum values for each key.(2016-01, url0), 2(2016-01, url1), 1"""yield key, sum(values)

4)我们需要有一个服务来删除过期的粘贴板

为了删除过期的粘贴板,我们可以扫描sql数据库:只要过期时间戳比当前时间旧,我们就可以直接删除。

第四步:扩展我们的设计

先找到瓶颈再解决问题。以下是我们的扩展设计图。

分析数据库可以使用例如Amazon Redshift或者Google BigQuery之类的数据仓库。
Amazon S3之类的面向对象存储可以轻松处理每个月12.7 GB的新增内容。
为了处理每秒40个读请求(峰值可能会略高),流行内容的读请求应该由内存缓存来处理而非数据库。内存缓存在处理不均匀的流量时也很有效。 The SQL Read Replicas should be able to handle the cache misses, as long as the replicas are not bogged down with replicating writes.(译者注:没看明白)
平均每秒的写操作对于 SQL Write Master-Slave是能够应付的。
(译者注:第四部分包含大量的链接以及面试技巧,此处不翻译,有需要的请看原文)
 

这篇关于系统设计面试题 之 如何设计Pastebin.com的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/824503

相关文章

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux查询服务器系统版本号的多种方法

《Linux查询服务器系统版本号的多种方法》在Linux系统管理和维护工作中,了解当前操作系统的版本信息是最基础也是最重要的操作之一,系统版本不仅关系到软件兼容性、安全更新策略,还直接影响到故障排查和... 目录一、引言:系统版本查询的重要性二、基础命令解析:cat /etc/Centos-release详

更改linux系统的默认Python版本方式

《更改linux系统的默认Python版本方式》通过删除原Python软链接并创建指向python3.6的新链接,可切换系统默认Python版本,需注意版本冲突、环境混乱及维护问题,建议使用pyenv... 目录更改系统的默认python版本软链接软链接的特点创建软链接的命令使用场景注意事项总结更改系统的默

在Linux系统上连接GitHub的方法步骤(适用2025年)

《在Linux系统上连接GitHub的方法步骤(适用2025年)》在2025年,使用Linux系统连接GitHub的推荐方式是通过SSH(SecureShell)协议进行身份验证,这种方式不仅安全,还... 目录步骤一:检查并安装 Git步骤二:生成 SSH 密钥步骤三:将 SSH 公钥添加到 github

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处