內容目錄
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