From 8149cc0f3d9253f6e31b8a0a2a6a3a26191e88f8 Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Thu, 25 Apr 2019 23:55:18 +0800 Subject: [PATCH 1/6] translate pastebin solution doc to chinese update update --- README-zh-Hans.md | 2 +- .../system_design/pastebin/README-zh-Hans.md | 330 ++++++++++++++++++ solutions/system_design/pastebin/README.md | 16 +- 3 files changed, 339 insertions(+), 9 deletions(-) create mode 100644 solutions/system_design/pastebin/README-zh-Hans.md diff --git a/README-zh-Hans.md b/README-zh-Hans.md index e337444a87..1ab9dd4336 100644 --- a/README-zh-Hans.md +++ b/README-zh-Hans.md @@ -300,7 +300,7 @@ | 问题 | | | ---------------------------------------- | ---------------------------------------- | -| 设计 Pastebin.com (或者 Bit.ly) | [解答](solutions/system_design/pastebin/README.md) | +| 设计 Pastebin.com (或者 Bit.ly) | [解答](solutions/system_design/pastebin/README-zh-Hans.md) | | 设计 Twitter 时间线和搜索 (或者 Facebook feed 和搜索) | [解答](solutions/system_design/twitter/README.md) | | 设计一个网页爬虫 | [解答](solutions/system_design/web_crawler/README.md) | | 设计 Mint.com | [解答](solutions/system_design/mint/README.md) | diff --git a/solutions/system_design/pastebin/README-zh-Hans.md b/solutions/system_design/pastebin/README-zh-Hans.md new file mode 100644 index 0000000000..0a6c7d75d3 --- /dev/null +++ b/solutions/system_design/pastebin/README-zh-Hans.md @@ -0,0 +1,330 @@ +# 设计 Pastebin.com (或者 Bit.ly) + +*Note: 为了避免重复,当前文档直接链接到[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)的相关区域,请参考链接内容以获得综合的讨论点、权衡和替代方案。* + +**设计 Bit.ly** - 是一个类似的问题,区别是 pastebin 需要存储的是 paste 的内容,而不是原始的未短化的 url。 + +## 第一步:概述用例和约束 + +> 收集这个问题的需求和范畴。 +> 问相关问题来明确用例和约束。 +> 讨论一些假设。 + +因为没有面试官来明确这些问题,所以我们自己将定义一些用例和约束。 + +### 用例 + +#### 我们将问题的范畴限定在如下用例 + +* **用户** 输入一段文本,然后得到一个随机生成的链接 + * 过期设置 + * 默认的设置是不会过期的 + * 可以选择设置一个过期的时间 +* **用户** 输入一个 paste 的 url 后,可以看到它存储的内容 +* **用户** 是匿名的 +* **Service** 跟踪页面分析 + * 一个月的访问统计 +* **Service** 删除过期的 pastes +* **Service** 需要高可用 + +#### 超出范畴的用例 + +* **用户** 可以注册一个账户 + * **用户** 通过验证邮箱 +* **用户** 可以用注册的账户登录 + * **用户** 可以编辑文档 +* **用户** 可以设置可见性 +* **用户** 可以设置短链接 + +### 约束和假设 + +#### 状态假设 + +* 访问流量不是均匀分布的 +* 打开一个短链接应该是很快的 +* pastes 只能是文本 +* 页面访问分析数据可以不用实时 +* 一千万的用户量 +* 每个月一千万的 paste 写入量 +* 每个月一亿的 paste 读取量 +* 读写比例在 10:1 + +#### 计算使用 + +**向面试官说明你是否应该粗略计算一下使用情况。** + +* 每个 paste 的大小 + * 每一个 paste 1 KB + * `shortlink` - 7 bytes + * `expiration_length_in_minutes` - 4 bytes + * `created_at` - 5 bytes + * `paste_path` - 255 bytes + * 总共 = ~1.27 KB +* 每个月新的 paste 内容在 12.7GB + * (1.27 * 10000000)KB / 月的 paste + * 三年内将近 450GB 的新 paste 内容 + * 三年内 3.6 亿短链接 + * 假设大部分都是新的 paste,而不是需要更新已存在的 paste +* 平均 4paste/s 的写入速度 +* 平均 40paste/s 的读取速度 + +简单的转换指南: + +* 2.5 百万 req/s +* 1 req/s = 2.5 百万 req/m +* 40 req/s = 1 亿 req/m +* 400 req/s = 10 亿 req/m + +## 第二步:创建一个高层次设计 + +> 概述一个包括所有重要的组件的高层次设计 + +![Imgur](http://i.imgur.com/BKsBnmG.png) + +## 第三步:设计核心组件 + +> 深入每一个核心组件的细节 + +### 用例:用户输入一段文本,然后得到一个随机生成的链接 + +我们可以用一个 [关系型数据库](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#关系型数据库管理系统rdbms)作为一个大的哈希表,用来把生成的 url 映射到一个包含 paste 文件的文件服务器和路径上。 + +为了避免托管一个文件服务器,我们可以用一个托管的**对象存储**,比如 Amazon 的 S3 或者[NoSQL 文档类型存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#文档类型存储)。 + +作为一个大的哈希表的关系型数据库的替代方案,我们可以用[NoSQL 键值存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#键-值存储)。我们需要讨论[选择 SQL 或 NoSQL 之间的权衡](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql)。下面的讨论是使用关系型数据库方法。 + +* **客户端** 发送一个创建 paste 的请求到作为一个[反向代理](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#反向代理web-服务器)启动的 **Web 服务器**。 +* **Web 服务器** 转发请求给 **写接口** 服务器 +* **写接口** 服务器执行如下操作: + * 生成一个唯一的 url + * 检查这个 url 在 **SQL 数据库** 里面是否是唯一的 + * 如果这个 url 不是唯一的,生成另外一个 url + * 如果我们支持自定义 url,我们可以使用用户提供的 url(也需要检查是否重复) + * 把生成的 url 存储到 **SQL 数据库** 的 `pastes` 表里面 + * 存储 paste 的内容数据到 **对象存储** 里面 + * 返回生成的 url + +**向面试官阐明你需要写多少代码** + +`pastes` 表可以有如下结构: + +```sql +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` 字段上创建一个[数据库索引](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#使用正确的索引),用来提高查询的速度(避免因为扫描全表导致的长时间查询)并将数据保存在内存中,从内存里面顺序读取 1MB 的数据需要大概 250 微秒,而从 SSD 上读取则需要花费 4 倍的时间,从硬盘上则需要花费 80 倍的时间。 1 + +为了生成唯一的 url,我们可以: + +* 使用 [**MD5**](https://en.wikipedia.org/wiki/MD5) 来哈希用户的 IP 地址 + 时间戳 + * MD5 是一个普遍用来生成一个 128-bit 长度的哈希值的一种哈希方法 + * MD5 是一致分布的 + * 或者我们也可以用 MD5 哈希一个随机生成的数据 +* 用[**Base 62**](https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/) 编码 MD5 哈希值 + * 对于 urls,使用 Base 62 编码 `[a-zA-Z0-9]` 是比较合适的 + * 对于每一个原始输入只会有一个 hash 结果,Base 62 是确定的(不涉及随机性) + * Base 64 是另外一个流行的编码方案,但是对于 urls,会因为额外的 `+` 和 `-` 字符串而产生一些问题 + * 以下[Base 62 伪代码](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) 执行的时间复杂度是 O(k),k 是数字的数量 = 7: + +```python +def base_encode(num, base=62): + digits = [] + while num > 0 + remainder = modulo(num, base) + digits.push(remainder) + num = divide(num, base) + digits = digits.reverse +``` + +* 取输出的前 7 个字符,结果会有 62^7 个可能的值,应该足以满足在 3 年内处理 3.6 亿个短链接的约束: + +```python +url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] +``` + +我们将会用一个公开的[**REST 风格接口 **](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest): + +```shell +$ curl -X POST --data '{"expiration_length_in_minutes":"60", \"paste_contents":"Hello World!"}' https://pastebin.com/api/v1/paste +``` + +Response: + +```json +{ + "shortlink": "foobar" +} +``` + +用于内部通信,我们可以用[RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc)。 + +### 用例:用户输入一个 paste 的 url 后可以看到它存储的内容 + +* **客户端** 发送一个获取 paste 请求到 **Web Server** +* **Web Server** 转发请求给 **读取接口** 服务器 +* **读取接口** 服务器执行如下操作: + * 在 **SQL 数据库** 检查这个生成的 url + * 如果这个 url 在 **SQL 数据库** 里面,则从 **对象存储** 获取这个 paste 的内容 + * 否则,返回一个错误页面给用户 + +REST API: + +```shell +curl https://pastebin.com/api/v1/paste?shortlink=foobar +``` + +Response: + +```json +{ + "paste_contents": "Hello World", + "created_at": "YYYY-MM-DD HH:MM:SS", + "expiration_length_in_minutes": "60" +} +``` + +### 用例: 服务跟踪分析页面 + +因为实时分析不是必须的,所以我们可以简单的 **MapReduce** **Web Server** 的日志,用来生成点击次数。 + +```python +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) +``` + +### 用例: 服务删除过期的 pastes + +为了删除过期的 pastes,我们可以直接搜索 **SQL 数据库** 中所有的过期时间比当前时间更早的记录, +所有过期的记录将从这张表里面删除(或者将其标记为过期) + +## 第四步:扩展这个设计 + +> 给定约束条件,识别和解决瓶颈。 + +![Imgur](http://i.imgur.com/4edXG0T.png) + +**重要提示: 不要简单的从最初的设计直接跳到最终的设计** + +说明您将迭代地执行这样的操作:1)**Benchmark/Load 测试**,2)**Profile** 出瓶颈,3)在评估替代方案和权衡时解决瓶颈,4)重复前面,可以参考[在 AWS 上设计一个可以支持百万用户的系统](../scaling_aws/README.md)这个用来解决如何迭代地扩展初始设计的例子。 + +重要的是讨论在初始设计中可能遇到的瓶颈,以及如何解决每个瓶颈。比如,在多个 **Web 服务器** 上添加 **负载平衡器** 可以解决哪些问题? **CDN** 解决哪些问题?**Master-Slave Replicas** 解决哪些问题? 替代方案是什么和怎么对每一个替代方案进行权衡比较? + +我们将介绍一些组件来完成设计,并解决可伸缩性问题。内部的负载平衡器并不能减少杂乱。 + +*为了避免重复的讨论*, 参考以下[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)获取主要讨论要点、权衡和替代方案: + +* [DNS](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#域名系统) +* [CDN](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#内容分发网络cdn) +* [负载均衡器](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#负载均衡器) +* [水平扩展](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#水平扩展) +* [反向代理(web 服务器)](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#反向代理web-服务器) +* [应用层](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用层) +* [缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存) +* [关系型数据库管理系统 (RDBMS)](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#关系型数据库管理系统rdbms) +* [SQL write master-slave failover](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#故障切换) +* [主从复制](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#主从复制) +* [一致性模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#一致性模式) +* [可用性模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#可用性模式) + +**分析存储数据库** 可以用比如 Amazon Redshift 或者 Google BigQuery 这样的数据仓库解决方案。 + +一个像 Amazon S3 这样的 **对象存储**,可以轻松处理每月 12.7 GB 的新内容约束。 + +要处理 *平均* 每秒 40 读请求(峰值更高),其中热点内容的流量应该由 **内存缓存** 处理,而不是数据库。**内存缓存** 对于处理分布不均匀的流量和流量峰值也很有用。只要副本没有陷入复制写的泥潭,**SQL Read Replicas** 应该能够处理缓存丢失。 + +对于单个 **SQL Write Master-Slave**,*平均* 每秒 4paste 写入 (峰值更高) 应该是可以做到的。否则,我们需要使用额外的 SQL 扩展模式: + +* [联合](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#联合) +* [分片](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#分片) +* [非规范化](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#非规范化) +* [SQL 调优](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#SQL调优) + +我们还应该考虑将一些数据移动到 **NoSQL 数据库**。 + +## 额外的话题 + +> 是否更深入探讨额外主题,取决于问题的范围和面试剩余的时间。 + +### NoSQL + +* [键值存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#键-值存储) +* [文档存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#文档类型存储) +* [列型存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#列型存储) +* [图数据库](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#图数据库) +* [sql 还是 nosql](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql) + +### 缓存 + +* 在哪缓存 + * [客户端缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#客户端缓存) + * [CDN 缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#cdn-缓存) + * [Web 服务器缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#web-服务器缓存) + * [数据库缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库缓存) + * [应用缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用缓存) +* 缓存什么 + * [数据库查询级别的缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库查询级别的缓存) + * [对象级别的缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#对象级别的缓存) +* 何时更新缓存 + * [缓存模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存模式) + * [直写模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#直写模式) + * [回写模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#回写模式) + * [刷新](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#刷新) + +### 异步和微服务 + +* [消息队列](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#消息队列) +* [任务队列](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#任务队列) +* [背压](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#背压) +* [微服务](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#微服务) + +### 通信 + +* 讨论权衡: + * 跟客户端之间的外部通信 - [HTTP APIs following REST](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest) + * 内部通信 - [RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc) +* [服务发现](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#服务发现) + +### 安全 + +参考[安全](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#安全). + +### 延迟数字 + +见[每个程序员都应该知道的延迟数](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数). + +### 持续进行 + +* 继续对系统进行基准测试和监控,以在瓶颈出现时解决它们 +* 扩展是一个迭代的过程 diff --git a/solutions/system_design/pastebin/README.md b/solutions/system_design/pastebin/README.md index 756c78c274..fc5bcf7407 100644 --- a/solutions/system_design/pastebin/README.md +++ b/solutions/system_design/pastebin/README.md @@ -70,7 +70,7 @@ Without an interviewer to address clarifying questions, we'll define some use ca Handy conversion guide: -* 2.5 million seconds per month +* 2.5 million requests per month * 1 request per second = 2.5 million requests per month * 40 requests per second = 100 million requests per month * 400 requests per second = 1 billion requests per month @@ -108,7 +108,7 @@ An alternative to a relational database acting as a large hash table, we could u The `pastes` table could have the following structure: -``` +```sql shortlink char(7) NOT NULL expiration_length_in_minutes int NOT NULL created_at datetime NOT NULL @@ -148,14 +148,14 @@ url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] We'll use a public [**REST API**](https://github.com/donnemartin/system-design-primer#representational-state-transfer-rest): -``` +```shell $ curl -X POST --data '{ "expiration_length_in_minutes": "60", \ "paste_contents": "Hello World!" }' https://pastebin.com/api/v1/paste ``` Response: -``` +```json { "shortlink": "foobar" } @@ -174,16 +174,16 @@ For internal communications, we could use [Remote Procedure Calls](https://githu REST API: -``` +```shell $ curl https://pastebin.com/api/v1/paste?shortlink=foobar ``` Response: -``` +```json { - "paste_contents": "Hello World" - "created_at": "YYYY-MM-DD HH:MM:SS" + "paste_contents": "Hello World", + "created_at": "YYYY-MM-DD HH:MM:SS", "expiration_length_in_minutes": "60" } ``` From ca677e0701c042ee107b5684271ca3b86402378f Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Thu, 30 May 2019 13:06:32 +0800 Subject: [PATCH 2/6] update --- solutions/system_design/pastebin/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/solutions/system_design/pastebin/README.md b/solutions/system_design/pastebin/README.md index fc5bcf7407..ca54a1bd12 100644 --- a/solutions/system_design/pastebin/README.md +++ b/solutions/system_design/pastebin/README.md @@ -70,7 +70,7 @@ Without an interviewer to address clarifying questions, we'll define some use ca Handy conversion guide: -* 2.5 million requests per month +* 2.5 million seconds per month * 1 request per second = 2.5 million requests per month * 40 requests per second = 100 million requests per month * 400 requests per second = 1 billion requests per month @@ -108,7 +108,7 @@ An alternative to a relational database acting as a large hash table, we could u The `pastes` table could have the following structure: -```sql +``` shortlink char(7) NOT NULL expiration_length_in_minutes int NOT NULL created_at datetime NOT NULL @@ -130,7 +130,7 @@ To generate the unique url, we could: * Base 64 is another popular encoding but provides issues for urls because of the additional `+` and `/` characters * The following [Base 62 pseudocode](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) runs in O(k) time where k is the number of digits = 7: -```python +``` def base_encode(num, base=62): digits = [] while num > 0 @@ -142,7 +142,7 @@ def base_encode(num, base=62): * Take the first 7 characters of the output, which results in 62^7 possible values and should be sufficient to handle our constraint of 360 million shortlinks in 3 years: -```python +``` url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] ``` @@ -155,7 +155,7 @@ $ curl -X POST --data '{ "expiration_length_in_minutes": "60", \ Response: -```json +``` { "shortlink": "foobar" } @@ -174,13 +174,13 @@ For internal communications, we could use [Remote Procedure Calls](https://githu REST API: -```shell +``` $ curl https://pastebin.com/api/v1/paste?shortlink=foobar ``` Response: -```json +``` { "paste_contents": "Hello World", "created_at": "YYYY-MM-DD HH:MM:SS", @@ -194,7 +194,7 @@ Since realtime analytics are not a requirement, we could simply **MapReduce** th **Clarify with your interviewer how much code you are expected to write**. -```python +``` class HitCounts(MRJob): def extract_url(self, line): From 4a02c5d0f14804df879b435fc75410c9a228e1ef Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Thu, 30 May 2019 13:08:20 +0800 Subject: [PATCH 3/6] update --- solutions/system_design/pastebin/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solutions/system_design/pastebin/README.md b/solutions/system_design/pastebin/README.md index ca54a1bd12..756c78c274 100644 --- a/solutions/system_design/pastebin/README.md +++ b/solutions/system_design/pastebin/README.md @@ -130,7 +130,7 @@ To generate the unique url, we could: * Base 64 is another popular encoding but provides issues for urls because of the additional `+` and `/` characters * The following [Base 62 pseudocode](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) runs in O(k) time where k is the number of digits = 7: -``` +```python def base_encode(num, base=62): digits = [] while num > 0 @@ -142,13 +142,13 @@ def base_encode(num, base=62): * Take the first 7 characters of the output, which results in 62^7 possible values and should be sufficient to handle our constraint of 360 million shortlinks in 3 years: -``` +```python url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] ``` We'll use a public [**REST API**](https://github.com/donnemartin/system-design-primer#representational-state-transfer-rest): -```shell +``` $ curl -X POST --data '{ "expiration_length_in_minutes": "60", \ "paste_contents": "Hello World!" }' https://pastebin.com/api/v1/paste ``` @@ -182,8 +182,8 @@ Response: ``` { - "paste_contents": "Hello World", - "created_at": "YYYY-MM-DD HH:MM:SS", + "paste_contents": "Hello World" + "created_at": "YYYY-MM-DD HH:MM:SS" "expiration_length_in_minutes": "60" } ``` @@ -194,7 +194,7 @@ Since realtime analytics are not a requirement, we could simply **MapReduce** th **Clarify with your interviewer how much code you are expected to write**. -``` +```python class HitCounts(MRJob): def extract_url(self, line): From 954d18c85866bbae7c8fad730f11625bddf6ab2a Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Tue, 4 Jun 2019 01:49:49 +0800 Subject: [PATCH 4/6] update --- solutions/system_design/pastebin/README-zh-Hans.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/solutions/system_design/pastebin/README-zh-Hans.md b/solutions/system_design/pastebin/README-zh-Hans.md index 0a6c7d75d3..c4d5d41a67 100644 --- a/solutions/system_design/pastebin/README-zh-Hans.md +++ b/solutions/system_design/pastebin/README-zh-Hans.md @@ -124,11 +124,11 @@ PRIMARY KEY(shortlink) * MD5 是一个普遍用来生成一个 128-bit 长度的哈希值的一种哈希方法 * MD5 是一致分布的 * 或者我们也可以用 MD5 哈希一个随机生成的数据 -* 用[**Base 62**](https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/) 编码 MD5 哈希值 +* 用 [**Base 62**](https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/) 编码 MD5 哈希值 * 对于 urls,使用 Base 62 编码 `[a-zA-Z0-9]` 是比较合适的 * 对于每一个原始输入只会有一个 hash 结果,Base 62 是确定的(不涉及随机性) * Base 64 是另外一个流行的编码方案,但是对于 urls,会因为额外的 `+` 和 `-` 字符串而产生一些问题 - * 以下[Base 62 伪代码](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) 执行的时间复杂度是 O(k),k 是数字的数量 = 7: + * 以下 [Base 62 伪代码](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) 执行的时间复杂度是 O(k),k 是数字的数量 = 7: ```python def base_encode(num, base=62): @@ -146,7 +146,7 @@ def base_encode(num, base=62): url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] ``` -我们将会用一个公开的[**REST 风格接口 **](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest): +我们将会用一个公开的 [**REST 风格接口**](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest): ```shell $ curl -X POST --data '{"expiration_length_in_minutes":"60", \"paste_contents":"Hello World!"}' https://pastebin.com/api/v1/paste @@ -160,7 +160,7 @@ Response: } ``` -用于内部通信,我们可以用[RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc)。 +用于内部通信,我们可以用 [RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc)。 ### 用例:用户输入一个 paste 的 url 后可以看到它存储的内容 @@ -227,7 +227,7 @@ class HitCounts(MRJob): ### 用例: 服务删除过期的 pastes 为了删除过期的 pastes,我们可以直接搜索 **SQL 数据库** 中所有的过期时间比当前时间更早的记录, -所有过期的记录将从这张表里面删除(或者将其标记为过期) +所有过期的记录将从这张表里面删除(或者将其标记为过期)。 ## 第四步:扩展这个设计 @@ -318,11 +318,11 @@ class HitCounts(MRJob): ### 安全 -参考[安全](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#安全). +参考[安全](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#安全)。 ### 延迟数字 -见[每个程序员都应该知道的延迟数](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数). +见[每个程序员都应该知道的延迟数](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数)。 ### 持续进行 From 8f09b07bb4202f4cbe5f1e4edffa56ffa588e14e Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Tue, 4 Jun 2019 16:27:39 +0800 Subject: [PATCH 5/6] update --- solutions/system_design/pastebin/README-zh-Hans.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/system_design/pastebin/README-zh-Hans.md b/solutions/system_design/pastebin/README-zh-Hans.md index c4d5d41a67..5e9564e80c 100644 --- a/solutions/system_design/pastebin/README-zh-Hans.md +++ b/solutions/system_design/pastebin/README-zh-Hans.md @@ -1,6 +1,6 @@ # 设计 Pastebin.com (或者 Bit.ly) -*Note: 为了避免重复,当前文档直接链接到[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)的相关区域,请参考链接内容以获得综合的讨论点、权衡和替代方案。* +**Note: 为了避免重复,当前文档直接链接到[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)的相关区域,请参考链接内容以获得综合的讨论点、权衡和替代方案。** **设计 Bit.ly** - 是一个类似的问题,区别是 pastebin 需要存储的是 paste 的内容,而不是原始的未短化的 url。 From 3a093caa656b6fe4981b63d87aaf5dc4b3053834 Mon Sep 17 00:00:00 2001 From: Kevin Xu Date: Tue, 4 Jun 2019 16:35:15 +0800 Subject: [PATCH 6/6] update --- solutions/system_design/pastebin/README-zh-Hans.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/system_design/pastebin/README-zh-Hans.md b/solutions/system_design/pastebin/README-zh-Hans.md index 5e9564e80c..b5fcbd3a0e 100644 --- a/solutions/system_design/pastebin/README-zh-Hans.md +++ b/solutions/system_design/pastebin/README-zh-Hans.md @@ -243,7 +243,7 @@ class HitCounts(MRJob): 我们将介绍一些组件来完成设计,并解决可伸缩性问题。内部的负载平衡器并不能减少杂乱。 -*为了避免重复的讨论*, 参考以下[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)获取主要讨论要点、权衡和替代方案: +**为了避免重复的讨论**, 参考以下[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)获取主要讨论要点、权衡和替代方案: * [DNS](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#域名系统) * [CDN](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#内容分发网络cdn)