内容目录
Toggle序言
Back-of-the-envelope 又称为封底计算,是用简单估算来计算复杂问题的近似值的方法。这边也复习一下,分散式系统由透过网路连接的运算节点组成。这些节点可以是各种类型的伺服器,例如网页伺服器、应用程式伺服器和储存伺服器。
在设计分散式系统时,了解每个节点可以处理的请求数量非常重要。同时我们也可以确定所需的节点数量以及流量,因此我们会使用Back-of-the-envelope 来去计算我们的粗估值,最终来设计我们所需的系统。
Back-of-the-envelope
在现实中,分散式系统由透过网路连接的运算节点组成,市面上的软体系统,也存在各式各样的运算节点,并且用许多不同的方式连接。 Back-of-the-envelope 可以帮助我们忽略系统的细节,专注于更重要的方面,如同前一篇文章提到的抽象概念。
以下是Back-of-the-envelope 的范例:
- 伺服器可以接受TCP 连接同时连结的数量。
- 网页、资料库或快取伺服器每秒可以处理的请求数量(RPS)。
- 服务的储存需求。
在上述这些情况中,如果计算出不合理的数字,可能会导致软体设计缺陷。因此在设计系统时,我们必须要使用Back-of-the-envelope 去做粗估,再去优化以及扩展我们的系统。
资料中心伺服器类型
资料中心并非只拥有一种类型的伺服器,企业解决方案使用商用硬体来降低成本,并且找出解法,来开发可扩展的系统,以下是资料中心内常用于处理不同工作负载(Workload)的伺服器类型:
网页伺服器(Web Server)
为了可扩展性,网页伺服器会与应用程式伺服器分开。网页伺服器是负载平衡器(Work Balancer)之后的第一个节点。网页伺服器也是处理用户端(Client Side)的API 呼叫的伺服器,通常内存以及储存资源根据需求会有不同。当然,通常内存、储存容量越大,伺服器就会有更良好的资源去做处理。例如:Meta 使用了32GB RAM 以及500GB 容量的伺服器,来满足大量的计算。
应用程式伺服器(Application Server)
应用程式伺服器用来处理,应用程式以及商业逻辑。不过网页伺服器以及应用程式伺服器通常不好区别,以下是他们两者之间的差异。应用程式伺服器提供动态的内容,网页伺服器则主要向用户端浏览器提供静态的内容。
储存伺服器(Storage Server)
随着网路越来越发达,任何网路服务也会因为流量与规模,需要储存的资料量也有爆炸式的增长,因此我们需要储存伺服器(可以理解成专门的资料库伺服器),来处理庞大的资料量。我们也需要根据不同的资料类型来去选择适当的资料库,例如: Youtube 使用以下的资料库:
- 使用Blob storage 来储存经过编译处理的影片资料。
- 使用Bigtable 来专门储存大量的影片缩图。
- 使用RDBMS 来储存使用者以及影片的资料,例如:评论、点赞资料。
- 使用SQL & NoSQL 来储存各种类型资料,用来做资料分析。
常见标准
系统服务的设计、规划、实作需要投入大量金钱、时间、人力。如果我们不清楚机器可以处理的工作负载类型,就很难进行更近一步的设计。延迟是一个非常重要的东西,来让我们可以判断哪些机器适合哪些工作负载,以下是从 Github 找到的资源,并且做成表格提供读者做参考。
延迟
项目 | 时间(奈秒) |
---|---|
执行一次指令 | 1/1,000,000,000 秒= 1 奈秒 |
从L1 快取记忆体提取 | 0.5 奈秒 |
分支预测错误 | 5 奈秒 |
从L2 快取记忆体提取 | 7 奈秒 |
Mutex 锁定/解锁 | 25 奈秒 |
从主记忆体提取 | 100 奈秒 |
通过1Gbps 网路传送2K 位元组 | 20,000 奈秒 |
从记忆体循序读取1MB | 250,000 奈秒 |
从新磁碟位置提取(seek) | 8,000,000 奈秒 |
从磁碟循序读取1MB | 20,000,000 奈秒 |
传送资料包到美国并返回 | 150 毫秒= 150,000,000 奈秒 |
QPS
除了上面列出的延迟之外,还有资料库每秒查询量Queries Per Second (QPS) ,用来衡量资料库查询的量。
重要速率 | 每秒查询量(QPS) |
---|---|
MySQL 处理的QPS | 1000 |
Key-Value 资料库处理的QPS | 10,000 |
快取器处理的QPS | 100,000 – 1 百万 |
单位量
指数 | 近似值 | 全名 | 简称 |
---|---|---|---|
10 | 千(Thousand) | Kilobyte | KB |
20 | 百万(Million) | Megabyte | MB |
30 | 十亿(Billion) | Gigabyte | GB |
40 | 兆(Trillion) | Terabyte | TB |
计算请求量
接下来讲解,什么是伺服器每秒可以处理的请求数量Requests Per Second(RPS)?
在伺服器内部,资源有限,根据客户端请求的类型,有可能造成系统瓶颈。
而我们主要可以分成两种类型的请求:
- CPU 密集型请求(CPU-bound requests): 此种请求的限制因素是CPU。
- 记忆体密集型请求(Memory-bound requests): 此种请求则是受到记忆体的限制。
CPU 密集型请求(CPU-bound requests)
计算CPU 密集型请求的RPS 的常用公式为:
RPS-CPU = Num-CPU x 1 / Task-Time
其中,每一个变数的意义如下:
- RPS-CPU:CPU 密集型的RPS
- Num-CPU:CPU 线程数量
- Task-time: 每个任务完成所需的时间
记忆体密集型请求(Memory-bound requests)
对于记忆体密集型请求,我们使用以下公式:
RPS-Memory = Worker-Memory / RAM-Size x 1 / Task-Time
其中,每一个变数的意义如下:
- RPS-Memory:记忆体密集型的RPS
- RAM-size:RAM 的大小
- Worker-Memory:记忆体用来管理记忆体的worker
服务会同时收到CPU 密集型和记忆体密集型请求。假设一半的请求是CPU 密集型,另一半是记忆体密集型,那么我们可以处理的总RPS 为:
RPS = (RPS-CPU + RPS-Memory) / 2
上面的计算只是为了理解估算RPS 的近似值,实际上,还有可能许多其他因素会影响RPS。例如:如果资料不在RAM 中,或向资料库伺服器发出请求,则需要进行磁碟寻道(Seek),从而产生延迟。其他因素包括:故障、程式码中的错误、节点故障、断电、网路中断…等,都是不可避免的因素。
系统设计面试中的计算类型
在系统设计面试中,我们可能需要进行以下几种类型的估算:
- 负载计算(Load estimation): 预测系统每秒预期的请求数量、数据量或用户流量。
- 储存空间计算(Storage estimation): 估算处理系统生成资料所需的储存空间量。
- 频宽计算(Bandwidth estimation): 预期流量和资料传输所需的网路频宽。
- 延迟计算(Latency estimation): 系统的架构和元件来预测响应时间和延迟。
- 资源计算(Resource estimation): 估算处理负载所需的伺服器、CPU 或内存数量。
封底计算实用范例
负载计算(Load estimation)
假设要设计一个社交媒体平台,拥有1 亿日活跃使用者(DAU) 且每个用户每天平均发布10 篇贴文。为了计算负载,我们需要计算每天生成的贴文总数:
1 亿DAU * 10 篇贴文/用户= 10 亿篇贴文/天
然后估算每秒的请求数量:
10 亿篇贴文/天/ 86,400 秒/天= 11,574 个请求/秒
储存空间计算(Storage estimation)
考虑一个拥有5 亿使用者的照片分享应用程式,每个使用者每天平均上传2 张照片。每张照片的平均大小为2 MB。要估算一天照片所需储存空间,计算如下:
5 亿使用者* 2 张照片/使用者* 2 MB/照片= 2,000,000,000 MB/天
频宽计算(Bandwidth estimation)
对于拥有1000 万使用者、以4 Mbps 串流1080p 影片的影片串流服务,可以计算所需的频宽:
1000 万使用者* 4 Mbps = 40,000,000 Mbps
延迟计算(Latency estimation)
假设要设计一个从多个来源获取资料的API,并且知道每个来源的平均延迟为50 毫秒、100 毫秒和200 毫秒,计算延迟如下:
50 毫秒+ 100 毫秒+ 200 毫秒= 350 毫秒
如果过程是平行(Parallel)的,则总延迟则会取最大的延迟:
max(50 毫秒, 100 毫秒, 200 毫秒) = 200 毫秒
资源计算(Resource estimation)
如果要设计一个每秒接收10,000 个请求的系统,每个请求需要10 毫秒的CPU 时间。要计算所需的CPU 核心数,可以单纯计算每秒的总CPU 时间:
10,000 个请求/秒* 10 毫秒/请求= 100,000 毫秒/秒
这时候可以另外假设每个CPU 每个核心可以处理1,000 毫秒的量,则所需的核心数量是:
100,000 毫秒/秒/ 1,000 毫秒/核心= 100 个核心
结论
Back-of-the-envelope 是一种快速估算系统需求的方法,可以用于系统设计的早期阶段。这个方法可以做出有效的设计决策,避免在后续阶段出现问题。
以下是一些使用Back-of-the-envelope 进行系统设计的注意事项:
- Back-of-the-envelope 只能提供粗略估算,如果真的有设计系统的情境,则需要详细分析。
- 在进行Back-of-the-envelope 时,需要考虑系统的所有主要因素,包括硬体、软体和网路。
引用
Teach Yourself Programming in Ten Years