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 Yahoo! Software Engineer 軟體工程師面試心得

zh_TW繁體中文