# System Design Interview Ch 2 粗略估算

在系統設計面試關卡中，經常會要求面試者粗略估算來評估**系統容量**或**效能需求**。估算的目的都是為了系統的**可擴展性（Scalability）**。

> back-of-the-envelope calculations are estimates you create using a combination of thought experiments and common performance numbers to get a good feel for which designs will meet your requirements
> 
> **粗略估算是你結合思想實驗和常見效能數據所創建的估算，用來了解哪些設計能滿足你的需求**

粗略估算不是要算得非常精確，而是在面試限時內，快速判斷系統容量、吞吐量、儲存與成本，並據此選擇合理架構。

```mermaid
mindmap
  root((系統設計：效能瓶頸與粗略估算))
    1 導言
      為什麼這一節很重要
      在整體系統設計學習中的位置
    2 效能瓶頸識別
      I/O 密集
        資料庫/磁碟/網路等待
      CPU 密集
        計算/編碼/加解密
      如何找瓶頸
        端到端延遲剖析
        監控指標：CPU/IO wait/吞吐/錯誤率
        單元壓測與隔離測試
    3 粗略估算思路
      Back-of-the-envelope 方法
      常用參考基準
        延遲數字 (Latency Numbers)
        單機 QPS（Web/DB）
        網路頻寬與 I/O 吞吐
      計算流程
        澄清需求：QPS/延遲/留存/可用性
        列出假設：DAU/讀寫比/資料大小/峰值係數
        計算 & Sanity Check
        形成結論與架構權衡
    4 關鍵組件性能測試
      資料庫 Benchmark
        典型查詢讀寫
        量測平均/P95/P99
      搜尋系統 Benchmark
        過濾/聚合/排序
      Cache Benchmark
        GET/SET 高併發
      產出
        QPS 上限
        延遲曲線
        錯誤率/超時門檻
    5 架構設計模式與優化
      Cache
        熱點資料/查詢結果快取
      Sharding
        水平切分/路由策略
      Replication
        主寫多讀/跨 AZ
      負載分散
        LB/Auto Scaling/健康檢查
      一致性策略
        強一致 vs 最終一致
      韌性與保護
        限流/熔斷/重試退避
        降級/Fallback
    6 案例演練（社交平台 1 億用戶）
      需求假設
        DAU/活躍比例/人均請求
        峰值係數
      推導
        平均 & 峰值 QPS
        Cache 命中率 → DB QPS
        儲存需求（每日/年度）
      規模估算
        前端/服務台數
        DB/Cache 節點數
        儲存硬體/雲成本級別
    7 權衡考量
      成本 vs 擴展性
      複雜性 vs 可維護性
      一致性 vs 可用性（CAP/延遲）
      故障恢復 vs 延遲開銷（RTO/RPO）
    8 總結與面試答題建議
      答題流程
        先定位瓶頸
        再做粗算
        說明 Benchmark 設計
        提方案與 trade-off
        白板簡圖標註 QPS/數據流
      常見陷阱
        只看平均不看峰值
        不分層 QPS（API/DB/Cache）
        忽略延遲分佈（P95/P99）
        忽略 Cache 對後端壓力的影響
```

## 🎯 系統設計中的效能瓶頸與粗略估算思維

在設計分散式系統時，首先要辨識出**整個鏈路中最關鍵的效能瓶頸**。  
如果系統的服務鏈中存在「主要吃硬碟的組件」──例如資料庫、搜尋引擎或訊息佇列──那麼整體\*\*吞吐量（Throughput）\*\*的上限，往往會由這類 I/O 密集服務所決定。

因此，**第一步**應該是根據實際業務場景，先對這些關鍵服務進行簡單的 **benchmark 測試**，例如測出資料庫在典型查詢下的 **QPS（Queries Per Second）上限**。  
一旦掌握這個數據，其他依賴該資料庫的上層服務（API、應用層、快取層等）就能以此為基準，推算整體的流量能力與系統擴展需求。

### 峰值（Peak QPS）與平均（Average QPS）

在設計系統時，我們不只關心平均值，更要關心「**尖峰時刻**」的請求量：

| 指標 | 定義 | 用途 |
| --- | --- | --- |
| **平均 QPS** | 一天總請求 ÷ 86400 秒 | 評估整體負載 |
| **峰值 QPS（Peak QPS）** | 峰值期間（例如 5 分鐘內）的最高每秒請求數 | 用於容量預估與壓測設計 |

### 常見誤區

1. ❌ 只看平均 QPS → 忽略尖峰期導致過載
    
2. ❌ 不區分層級 → API 與 DB QPS 不等
    
3. ❌ 忽略 Cache 命中率 → 實際 DB QPS 大幅下降
    
4. ❌ 不看延遲分佈（P95/P99） → 高延遲請求導致併發壅塞
    

### 用 QPS 做容量預估

若單台伺服器可承受 5,000 QPS，  
服務預估峰值為 25,000 QPS，

則需要：`伺服器台數 = 峰值 QPS ÷ 每台 QPS = 25,000 ÷ 5,000 = 5 台`

加上冗餘與健康檢查，通常會部署 **N+1 或 N+2 架構**：  
→ 最終部署 6～7 台。

#### 步驟

\**澄清需求*

* QPS（Queries Per Second）: 每秒完成的請求數（Requests / second） = 總請求數 ÷ 總時間（秒）
    
    * 一個 API 伺服器在 10 秒內處理完了 50,000 次請求  
        → QPS = 50,000 ÷ 10 = **5,000 QPS**
        
* 吞吐量、資料留存時間、延遲要求
    
* 讀寫比、資料體積、可用性目標
    

**列出假設**

* 使用者數量／活躍比例（DAU/MAU）
    
* 平均單請求／單筆資料大小
    
* 工作負載分佈（讀多寫少、峰值因子）
    

**套用常見性能數字**

* Latency Numbers
    
* 單機機器能承受的 QPS（HTTP 伺服器、資料庫）
    
* 網路頻寬與 I/O 吞吐
    

**計算 & Sanity Check**

* 計算出 QPS、頻寬需求、每日／每年儲存量
    
* 把結果拿回「常識」比對：
    
    * 每秒幾千 QPS 需幾台 Web 伺服器？
        
    * 幾 TB 資料／天要多少硬碟？
        

**形成結論與權衡**

* 是否需要 Cache、分片、CDN、流量削峰…
    
* 預估硬體／雲端成本級別
    

# 每個系統工程師都應該知道的Delay數字

透過\[**Latency Numbers Every Programmer Should Know網站**\]([https://colin-scott.github.io/personal\_website/research/interactive\_latency.html](https://colin-scott.github.io/personal_website/research/interactive_latency.html))

**我們得出以下結論：**

* **記憶體很快，但磁碟很慢**
    
* **盡可能避免磁碟尋址**
    
* **簡單的壓縮演算法很快**
    
* **如果可能的話，在透過網際網路傳送資料前先壓縮**
    
* **資料中心通常位於不同地區，在它們之間傳送資料需要時間**
    

這些延遲數字揭示了現代電腦系統的效能特性：

### ⚡ **速度階層**

1. **CPU 快取/記憶體**：奈秒級別
    
2. **SSD 存取**：微秒級別
    
3. **網路通訊**：毫秒級別
    
4. **機械硬碟**：毫秒級別（最慢）
    

### 🎯 **設計原則**

* **記憶體優先**：盡量將熱點資料保存在記憶體中
    
* **避免磁碟 I/O**：特別是隨機存取，或者將 I/O 操作批次化
    
* **善用壓縮**：網路傳輸前壓縮資料
    
* **就近部署**：減少跨地區的資料傳輸
    

這些基準數字是系統設計決策的重要依據，幫助我們識別效能瓶頸並選擇合適的架構策略。

## 範例：估算 Twitter 的 QPS 和儲存需求

請注意以下數字僅用於此練習，並非 Twitter 的真實數據。

### **假設條件：**

* 3 億月活躍用戶
    
* 50% 的用戶（1.5億）每天使用 Twitter
    
* 用戶平均每天發布 2 則推文（3億篇推文）
    
* 10% 的推文包含媒體
    
* 資料儲存 5 年
    

**估算：**

**QPS 估算：**

* 日活躍用戶（DAU）= 3 億 × 50% = 1.5 億
    
* 推文 QPS = 1.5 億 × 2 則推文 ÷ 24 小時 ÷ 3600 秒 ≈ 3 500 qps
    
* 尖峰 QPS ≈ 2× 平均 = 7 000 qps
    

**媒體儲存量估算：**

* 平均推文大小：
    
    * tweet\_id：64 bytes
        
    * 文字：140 bytes
        
    * 媒體：1 MB
        
* 推文文本：3e8 × 200 bytes ≈ 60 GB／天
    
* 媒體儲存：1.5 億 × 2 × 10% × 1 MB = 30 TB／天
    
* 5 年媒體儲存：30 TB × 365 × 5 = ~55 PB
    

**Sanity Check**

* 7 000 qps → 假設一台 Nginx + App 能承 5 000 qps → 2–3 台即可
    
* 55 PB → 若單機硬碟 20 TB → 約 3 000 顆分散式儲存
    

#### **📊 常見的粗略估算問題**

QPS、Peak QPS、儲存、Cache 機制、伺服器數量等。準備面試時可以練習這些計算。

## 高可用（High Availability）

**高可用性**是指系統能夠在理想的長時間內持續運作的能力。高可用性以**百分比**來衡量，100% 表示服務的停機時間為 0。大多數服務的可用性介於 99% 到 100% 之間。

\*\*服務等級協議（SLA）\*\*是服務提供商常用的術語。這是你（服務提供商）與客戶之間的協議，正式定義了你的服務將提供的正常運行時間等級。雲端服務提供商 Amazon \[4\]、Google \[5\] 和 Microsoft \[6\] 將他們的 SLA 設定在 99.9% 或以上。正常運行時間傳統上以「幾個 9」來衡量。9 的數量越多越好。9 的數量與預期的系統停機時間相關。

**可用性等級對照**

* **99%** = 每年 3.65 天停機時間
    
* **99.9%** = 每年 8.76 小時停機時間
    
* **99.99%** = 每年 52.56 分鐘停機時間
    
* **99.999%** = 每年 5.26 分鐘停機時間
    

\*\*高可用性（High Availability, HA）\*\*不只是追求「幾個九」的可用率，更是一整套在架構、運維和測試上保障服務不中斷的具體措施。  
可用率計算公式

### 可用性計算的複雜性

**基礎公式：**

```scss

可用性 = MTBF / (MTBF + MTTR)
```

* MTBF（Mean Time Between Failures）平均故障間隔
    
* MTTR（Mean Time To Repair）平均修復時間
    

提高可用率的兩大思路：

1. 增加 MTBF → 系統更穩定、故障頻率下降
    
2. 降低 MTTR → 快速偵測、快速恢復
    

## 可用性 vs. 可靠性 vs. 耐久性

* **Availability（可用性）**：系統可「對外提供服務」的時間比例。
    
* **Reliability（可靠性）**：系統在指定時間內正確執行功能的概率。
    
* **Durability（耐久性）**：資料不遺失的程度（一般用在 Storage/Backup）
    

> 在 SLA 條款中若同時談「資料遺失賠償」，通常就是在講耐久性（Durability）。

**實際案例對比：**

| 場景 | 可用性 | 可靠性 | 耐久性 |
| --- | --- | --- | --- |
| 系統回應但資料錯誤 | ✅ 高 | ❌ 低 | ✅ 高 |
| 系統離線但資料完整 | ❌ 低 | ❌ 低 | ✅ 高 |
| 系統正常但資料遺失 | ✅ 高 | ❌ 低 | ❌ 低 |
| 理想狀態 | ✅ 高 | ✅ 高 | ✅ 高 |

### 關鍵指標：SLI / SLO / SLA

* **SLI (Service Level Indicator)**  
    用於衡量系統健康度的指標，如「成功響應率」「99% 響應時間 ≤ 500 ms」等。
    
* **SLO (Service Level Objective)**  
    你對 SLI 設定的目標值。例如「每月成功響應率 ≥ 99.9%」。
    
* **SLA (Service Level Agreement)**  
    對客戶承諾的可用率（通常 ≥ 99.9%），並與未達標時的賠償機制綁定。
    

**大型系統的現實挑戰：**

**串聯系統（Serial）**

```css
總可用性 = A₁ × A₂ × A₃ × ... × Aₙ
```

* 3個99.9%的服務串聯 = 99.7%
    
* 10個99.9%的服務串聯 = 99.0%
    

**並聯系統（Parallel）**

```css
總不可用性 = (1-A₁) × (1-A₂) × ... × (1-Aₙ)
總可用性 = 1 - 總不可用性
```

* 2個99.9%的服務並聯 = 99.9999%
    

**混合架構計算範例**

```css
Web層：2台並聯 (99.9% each) → 99.9999%
App層：3台並聯 (99.5% each) → 99.9875%
DB層：主從架構 (99.95%) → 99.95%

總可用性 = 99.9999% × 99.9875% × 99.95% ≈ 99.937%
```

一個大型服務往往包含多個 API Endpoint，要衡量「可用性」時，就要先明確定義你的 SLI（Service Level Indicator）和 SLO（Service Level Objective）針對哪個粒度：

**可用性粒度（Granularity）**

1. Endpoint 級別
    
    * 每個 API 路徑（如 `/login`、`/orders`、`/users/{id}`）都設定獨立的 SLI
        
    * 適合用於：不同 Endpoint 負責不同商業功能，對可用性要求差異大
        
2. 服務（Service）級別
    
    * 把所有或一組關鍵 Endpoint 聚合起來，計算整體成功率
        
    * 適合用於：只關注「整個服務可用／不可用」，不細分各路徑
        
3. 流量加權（Weighted）
    
    * 根據流量大小或業務重要性，給不同 Endpoint 不同權重
        
    * 例如：`/checkout` 佔總流量 20%，`/search` 佔 50%，按流量加權後算出「加權可用率」
        

假設我們把 `/login`、`/checkout`、`/search` 三個 Endpoint 聚合成「電子商務服務」：

* **SLI**：
    
    * **successful\_requests** = 請求數中返回 2xx 的次數
        
    * **total\_requests** = 所有到達三個 Endpoint 的請求
        
    * **availability** = successful\_requests / total\_requests
        
* **SLO**：
    
    * 每分鐘可用率 ≥ 99.9%
        
    * 429 回應佔比上限 ≤ 1%。**429 (Too Many Requests)**：屬於「流量保護/限流」，有時不算系統故障，但使用者無法完成操作，可視為可用性下降
        
* **SLA**：
    
    * 客戶承諾月度可用率 ≥ 99.9%，若低於則賠償
        

## 從 SLO 要求到架構設計

1. ### **收到 SLO / SLA 要求 → 定義 SLIs**
    
    * 與 SRE / 架構師一起確認：  
        • 哪些 Endpoint、哪些指標要算進可用率？  
        • Time window（1 min / 5 min / 30 days rolling）  
        • 流量是否加權？
        
    * 範例：  
        SLO：  
        • 成功回應率 ≥ 99.9%（2xx）  
        • p99 Latency ≤ 500 ms  
        • 429 限流率 ≤ 1%
        
    
    ### SLI 設計的層次化思維
    
    #### **業務層 SLI（Business-Level SLI）**
    
    ```yaml
    # 電商系統範例
    business_sli:
      order_success_rate:
        definition: "成功完成訂單 / 嘗試下單次數"
        target: "> 99.5%"
        
      payment_success_rate:
        definition: "支付成功 / 支付嘗試次數"  
        target: "> 99.9%"
        
      search_relevance:
        definition: "用戶點擊前3個搜尋結果的比例"
        target: "> 85%"
    ```
    
    #### **系統層 SLI（System-Level SLI）**
    
    ```yaml
    system_sli:
      api_availability:
        definition: "2xx回應 / 總請求數"
        measurement_window: "1分鐘"
        target: "> 99.9%"
        
      latency_p99:
        definition: "99%請求的回應時間"
        target: "< 500ms"
        
      error_rate:
        definition: "5xx錯誤 / 總請求數"
        target: "< 0.1%"
    ```
    
    #### **基礎設施層 SLI（Infrastructure-Level SLI）**
    
    ```yaml
    
    infrastructure_sli:
      cpu_utilization:
        target: "< 70% (sustained)"
        
      memory_utilization:
        target: "< 80%"
        
      disk_io_wait:
        target: "< 10%"
    ```
    
    ### 複雜系統的 SLO 分層設計
    
    #### **金字塔式 SLO 架構**
    
    ```java
    
    ┌─────────────────────────────────────┐
    │        Business SLO (99.5%)        │  ← 對客戶承諾
    ├─────────────────────────────────────┤
    │      Service SLO (99.7%)           │  ← 內部目標
    ├─────────────────────────────────────┤
    │   Component SLO (99.9%)            │  ← 元件目標  
    ├─────────────────────────────────────┤
    │ Infrastructure SLO (99.95%)        │  ← 基礎設施
    └─────────────────────────────────────┘
    ```
    
    **實際案例：微服務電商系統**
    
    ```yaml
    
    # 業務層 SLO
    business_slo:
      checkout_flow:
        slo: "99.5% 成功率"
        error_budget: "0.5% = 3.6小時/月"
        
    # 服務層 SLO  
    service_slo:
      user_service:
        availability: "99.8%"
        latency_p95: "< 200ms"
        
      order_service:
        availability: "99.9%"
        latency_p95: "< 300ms"
        
      payment_service:
        availability: "99.95%"  # 更嚴格，因為影響收入
        latency_p95: "< 500ms"
    
    # 基礎設施 SLO
    infrastructure_slo:
      kubernetes_cluster:
        node_availability: "99.95%"
        
      database:
        availability: "99.99%"
        replication_lag: "< 1s"
    ```
    
    ## 大型複雜系統的可用性架構設計
    
    ### 多層次冗餘設計
    
    #### **地理分散架構**
    
    ```yaml
    global_architecture:
      regions:
        - name: "us-east-1"
          role: "primary"
          capacity: "60%"
          
        - name: "us-west-2"  
          role: "secondary"
          capacity: "40%"
          
        - name: "eu-west-1"
          role: "disaster_recovery"
          capacity: "100% (cold standby)"
    
      failover_strategy:
        rto: "< 5 minutes"  # Recovery Time Objective
        rpo: "< 30 seconds" # Recovery Point Objective
    ```
    
    #### **服務網格容錯模式**
    
    ```yaml
    
    service_mesh_patterns:
      circuit_breaker:
        failure_threshold: 50%
        timeout: 30s
        reset_timeout: 60s
        
      retry_policy:
        max_attempts: 3
        backoff: "exponential"
        base_delay: 100ms
        max_delay: 10s
        
      bulkhead:
        thread_pools:
          critical_operations: 20
          normal_operations: 10
          background_tasks: 5
    ```
    
    ### 資料層可用性設計
    
    #### **分散式資料庫策略**
    
    ```yaml
    database_architecture:
      primary_db:
        type: "PostgreSQL"
        availability: "99.95%"
        backup_strategy:
          - continuous_wal_archiving
          - daily_full_backup
          - cross_region_replication
          
      read_replicas:
        count: 3
        distribution:
          - same_az: 1
          - different_az: 2
        lag_threshold: "< 100ms"
        
      cache_layers:
        l1_cache: "Application Memory"
        l2_cache: "Redis Cluster"
        l3_cache: "CDN"
        
      consistency_model:
        writes: "strong_consistency"
        reads: "eventual_consistency_acceptable"
    ```
    
    #### **資料分片與路由**
    
    ```python
    # 資料分片策略範例
    class ShardingStrategy:
        def __init__(self):
            self.shards = {
                'shard_1': {'range': '0-999999', 'master': 'db1', 'replicas': ['db1r1', 'db1r2']},
                'shard_2': {'range': '1000000-1999999', 'master': 'db2', 'replicas': ['db2r1', 'db2r2']},
                'shard_3': {'range': '2000000-2999999', 'master': 'db3', 'replicas': ['db3r1', 'db3r2']}
            }
        
        def route_query(self, user_id):
            shard_key = user_id % 3
            return self.shards[f'shard_{shard_key + 1}']
        
        def handle_shard_failure(self, failed_shard):
            # 自動故障轉移到副本
            replicas = self.shards[failed_shard]['replicas']
            return replicas[0]  # 提升第一個副本為主庫
    ```
    
    ### **2\. 架構 & 技術選型**
    
    根據 SLIs/SLOs 把可用性拆解到各層面需要採取的措施：
    
    | 層級 | 措施範例 |
    | --- | --- |
    | 基礎架構 | ■ 多可用區域（AZ）或 Region 部署 |
    | ■ Anycast DNS / Global LB |  |
    | 計算層 | ■ Auto-Scaling + Health Check |
    | ■ 多實例冗餘，避免單點故障 |  |
    | 資料儲存層 | ■ 多副本／分片（Replication / Sharding） |
    | ■ 定期備份，異地災難備援 |  |
    | 網路 & 流量管理 | ■ Load Balancer + Rate Limiter |
    | ■ CDN / Edge Cache |  |
    | ■ Circuit Breaker |  |
    | 運維 & 驗證 | ■ 監控 + Alert（Prometheus + Alertmanager） |
    | ■ Chaos Engineering |  |
    
    ### **3\. 實作步驟**
    
    **1\. 指標蒐集（Instrumentation）**
    
    * 在程式碼中**埋點**（metrics）  
        • 請求量、成功/失敗次數、延遲時間、限流次數…
        
    * 選擇收集與視覺化工具  
        • Prometheus + Grafana、Datadog、New Relic
        
    
    **2\. 自動化部署**
    
    * IaC（Infrastructure as Code）：Terraform、CloudFormation
        
    * CI/CD 流程：
        
        1. 單元測試 → 2. 整合測試 → 3. 部署到 Canary / Staging → 4. 觀察 SLI 指標 → 5. 全量上線
            
    
    **3\. 容錯 & 降級設計**
    
    * Circuit Breaker（斷路器）
        
    * Bulkhead（隔艙模式）
        
    * Timeout、Retry、Fallback → 保護下游服務
        
    
    **4\. 災難恢復**
    
    * 訂定 RPO / RTO，落實冷備 / 熱備方案
        
    * 定期演練「主機房失效切換」（DR Drill）
        
    
    ### **4\. 監控、告警與運維**
    
    1. Dashboard
        
        * 實時展示 SLI（成功率、Latency、Error Budget）
            
        * 結合業務指標（流量、訂單量）預測壓力
            
    2. Alert
        
        * 分級告警：P1（系統不可用）、P2（延遲升高）、P3（資源飽和）
            
        * 設定告警門檻、告警頻率（避免告警風暴）
            
    3. 事件管理
        
        * PagerDuty / Opsgenie on‐call
            
        * Blameless Postmortem（無責任歸屬的事故分析）
