引用:
系统设计入门
设计 Pastebin.com (或者 Bit.ly)
什么是 Pastebin.com,提供文本分享服务,例如用户A将某段文本复制进去,生成一个网址URL,用户B访问这个网址URL可以看到用户A输入的文本。
例子:https://pastebin.com/r4tkgw7M
什么是 Bit.ly,提供短地址服务,例如用户A将某个网址URL复制进去,生成一个短地址URL,用户B访问这个短地址URL可以自动跳转到原网址URL。
例子:https://bit.ly/1CjWhlk
第一步:通过讨论,明确限制及用例,确定Scope
支持的用例:
- 用户输入一段文本,得到一个link
- 默认该link没有截止日期
- 用户可以手动设定截止日期,例如1天,1周,1个月等等
- 用户在浏览器中访问link,可以看到之前输入的文本
- 系统统计页面的访问信息(每月)
- 系统删除已过期的link
- 系统高可用 high availability
不支持的用例:
- 不支持用户注册及登录
- 不支持用户设置link的可见性
- 不支持用户修改link
Constraints and assumptions:
- 访问不均匀
- 输入只能是纯文本,不能是图片及其他
- 页面访问信息的统计不需要是实时的
- 10 million 用户
- 每月 10 million 写操作,每秒4次 (每月2.5 million 秒)
- 每月 100 million 读操作,每秒40次
- 读写比例 10 :1
计算规模:
对于每一个文本:
- 文本内容:1 KB
- 短网址:7 bytes
- 截止时间:4 bytes
- 创建时间:5 bytes
- 文本路径:255 bytes
- 总共: ~1.27 KB
对于每一个月:
- 新文本内容:12.7 GB = 1.27 KB * 10 million
- 三年:~450 GB = 12.7 GB * 36
第二步:高层次设计
设计 Pastebin.com (或者 Bit.ly)第三步:设计核心组件
使用关系型数据库SQL存储短网址与文本的对应关系。例如创建一个表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)
文本的具体内容存储在 Object Store 中,可以是 Amazon S3,或者文档型的NoSQL,例如 MongoDB,key为 paste_path
。
此处可以讨论讨论 SQL VS NoSQL。
对于shortlink的产生,使用MD5加密算法:
- 使用用户的 IP + timestamp 进行 MD5 哈希
- 均匀分布,产生128位的哈希值(32 bytes,32个字符)
- 取前7个字符作为 shortlink,大概有627中取值,够用了。为啥是62?62=26 + 26 + 10(字母大小写及数字)。
对于Write API:设计为一个REST API
- 利用上述方法,产生shortlink。查询数据表
pastes
,判断是否重复了,如果有重复,需要重新生成shortlink。 - 插入一条数据到数据表
pastes
。 - 将文本的具体内容存储在 Object Store中。
- 返回shortlink。
对于Read API:设计为一个REST API
- 通过shortlink查询数据表
pastes
:- 如果存在,利用paste_path查询Object Store,返回文本的具体内容。
- 如果不存在,返回错误信息。
对于Analytics:
由于页面访问信息的统计不需要是实时的,我们可以使用 MapReduce 来分析 Web Server 的日志文件。Map 主要对日志做简单的拆分计数,Reduce 对 Map 的结果求和。
例如:
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), 1
def reducer(self, key, values):
"""Sum values for each key.
(2016-01, url0), 2
(2016-01, url1), 1
"""
yield key, sum(values)
删除过期的link:
- 扫描数据库中的所有行,比较截止日期。
第四步:扩展设计
设计 Pastebin.com (或者 Bit.ly)- 为了服务不同区域的用户,加快访问的速度,使用CDN加速,并缓存文本内容。
- 为了同时响应更多请求,对服务器水平扩展,并使用Load Balancer做负载均衡。
- 存储分析结果的数据 SQL Analytics 可以使用数据仓库,例如Amazon Redshift 或者 Google BigQuery.
- BigQuery 是 Google 推出的可扩展性强、成本低廉的无服务器企业数据仓库,可让您的所有数据分析人员更加高效地工作。不到一分钟便可设置好您的数据仓库并立即开始查询您的数据。Google BigQuery 可对 GB 级到 PB 级的数据执行极快速的 SQL 查询,并可轻松地将公共数据集或商业数据集与您的数据融合在一起。
- 为了加快读取效率,使用Memory Cache,存储 shortlink 和 paste_path 的对应关系,避免频繁访问数据库。
- 由于是读多写少,可以采用主从复制的数据库模式。主库同时负责读取和写入操作,并复制写入到一个或多个从库中,从库只负责读操作。
网友评论