Back-of-the-envelope 封底计算– 系统设计04

system-design-系统设计04-封底计算-back-of-the-envelope-hogantech-hoganblab

序言

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 奈秒
从记忆体循序读取1MB250,000 奈秒
从新磁碟位置提取(seek)8,000,000 奈秒
从磁碟循序读取1MB20,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),从而产生延迟。其他因素包括:故障、程式码中的错误、节点故障、断电、网路中断…等,都是不可避免的因素。

系统设计面试中的计算类型

在系统设计面试中,我们可能需要进行以下几种类型的估算:

  1. 负载计算(Load estimation): 预测系统每秒预期的请求数量、数据量或用户流量。
  2. 储存空间计算(Storage estimation): 估算处理系统生成资料所需的储存空间量。
  3. 频宽计算(Bandwidth estimation): 预期流量和资料传输所需的网路频宽。
  4. 延迟计算(Latency estimation): 系统的架构和元件来预测响应时间和延迟。
  5. 资源计算(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

相关文章

软体设计非功能性特性– 系统设计03

抽象在系统设计中的应用– 系统设计02

现代系统设计入门 - 系统设计 01

2023 雅虎软件工程师 软件工程师面试

zh_CN简体中文