Scale From Zero To Millions Of Users

Scale From Zero To Millions Of Users #

本章探討系統如何從最簡單的單一伺服器架構,逐步演進到能支援百萬級使用者的分散式系統。


1. 設置單一伺服器 (Single Server) #

最簡單的 Web 應用架構只需要一台伺服器,包含 Web Server、應用程式和資料庫。

single-server.png

運作流程

  1. 使用者透過網域名稱 (Domain Name) 向 DNS 查詢目標網站的 IP 位址
  2. DNS 回傳 IP 位址 (Internet Protocol)
  3. 瀏覽器向此 IP 發送 HTTP 請求 (Hypertext Transfer Protocol)
  4. 伺服器處理請求並回傳 HTML,瀏覽器渲染出網頁

適用場景:小型應用、MVP、個人專案


2. 獨立出資料庫 (Database) #

隨著使用者增加,將資料庫從 Web Server 分離能提升效能與可擴展性。

資料庫選擇 #

database.png

關聯式資料庫 (RDBMS)

  • MySQL、PostgreSQL、Oracle
  • 適用於結構化資料、需要 ACID 特性
  • 發展成熟,適用於大多數場景

非關聯式資料庫 (NoSQL)

  • MongoDB、Cassandra、DynamoDB、Redis
  • 適用於以下情境:
    • 需要極低延遲 (ultra-low latency)
    • 資料無固定結構或不需要關聯性
    • 只需進行序列化/反序列化操作
    • 資料量極為龐大

3. 規模擴展 (Scaling) 的方向選擇 #

當單一伺服器無法負荷流量時,有兩種擴展方向:

垂直擴展 (Vertical Scaling) #

  • 做法:升級單台機器的硬體(CPU、RAM、Storage)
  • 優點:實作簡單、快速見效
  • 缺點
    • 硬體能力有上限
    • 存在單點故障 (Single Point of Failure, SPOF)
    • 成本隨規模急遽上升

水平擴展 (Horizontal Scaling) #

  • 做法:增加更多伺服器來分散流量
  • 優點
    • 無硬體上限
    • 提升系統容錯能力
    • 適合大規模應用
  • 缺點:架構複雜度提升

建議:對於大型系統,水平擴展是更好的選擇


4. 設置負載平衡器 (Load Balancer) #

load-balancer.png

採用水平擴展後,需要負載平衡器來分配流量。

運作原理 #

  • 負載平衡器作為使用者與伺服器之間的橋樑
  • 伺服器使用私有 IP 互相通訊(不對外公開)
  • 使用者只知道負載平衡器的公開 IP

帶來的好處 #

  • 流量分散:避免單一伺服器過載
  • 高可用性:某台伺服器下線時,流量自動轉向其他伺服器
  • 彈性部署:可輕鬆增減伺服器數量

5. 備份資料庫 (Database Replication) #

database-replication-1.png

資料庫也需要容錯機制,常見做法是採用主從架構 (Master-Slave)。

主從架構 #

  • 主資料庫 (Master):處理寫入操作(INSERT、UPDATE、DELETE)
  • 從資料庫 (Slave):處理讀取操作,並同步主資料庫的資料

優勢 #

  • 效能提升:讀寫分離,提高並行處理能力
  • 可靠性:即使某個從資料庫損壞,資料仍可從其他副本取得
  • 高可用性:某台資料庫下線,其他資料庫仍可運作

故障處理 #

  • 從資料庫下線

    • 若只有一台從資料庫,讀取請求暫時導向主資料庫
    • 盡快部署新的從資料庫
  • 主資料庫下線

    • 提升一台從資料庫為新的主資料庫
    • 使用資料恢復腳本找回可能遺失的資料
    • 考慮採用多主架構自動容錯轉移機制

database-replication-2.png


6. 導入快取 (Cache) #

cache.png

快取將常用資料存入記憶體,大幅減少資料庫查詢次數。

運作流程 #

  1. 伺服器收到請求,先檢查快取
  2. 快取命中 (Cache Hit):直接回傳資料
  3. 快取未命中 (Cache Miss):從資料庫查詢,並寫入快取

設計考量 #

考量點說明
適用資料常被存取且較少更動的資料
過期時間 (TTL)不宜過短(效益低)或過長(資料可能過時)
資料一致性確保快取與資料庫資料同步
避免單點故障使用多個快取節點(如 Redis Cluster)
驅逐政策當容量不足時,採用 LRU、LFU 或 FIFO 策略

常用快取解決方案:Redis、Memcached


7. 設置 CDN (Content Delivery Network) #

cdn-1.png

CDN 用於快速分發靜態內容(圖片、影片、CSS、JavaScript)。

運作原理 #

  • 將靜態資源部署到全球各地的邊緣節點
  • 使用者從最近的節點取得資源,降低延遲

設計考量 #

  • 成本評估:CDN 服務需付費,評估使用頻率是否划算
  • 設定過期時間:確保內容適時更新
  • 備援機制:CDN 故障時,伺服器能作為備案
  • 版本管理:透過 URL 加上版本號(如 style.v2.css)控制更新
  • 內容失效:使用 CDN 供應商的 API 清除過時內容

cdn-2.png


8. 使網頁層無狀態 (Stateless Web Tier) #

stateless.png

為了實現水平擴展,Web Server 必須是無狀態的。

有狀態 vs 無狀態 #

有狀態 (Stateful)

  • Session 資料存在伺服器記憶體中
  • 使用者請求必須路由到同一台伺服器
  • 限制了負載平衡的彈性

無狀態 (Stateless)

  • Session 資料存在共享儲存(如 Redis、資料庫)
  • 任何伺服器都能處理任何請求
  • 易於擴展與部署

9. 建置資料中心 (Data Centers) #

data-center.png

為了服務全球使用者,需要在不同地理位置建立多個資料中心。

優勢 #

  • 降低延遲:使用者連接到最近的資料中心
  • 高可用性:某個資料中心故障,流量轉移到其他資料中心

實作要點 #

  • GeoDNS 路由:根據使用者地理位置導向最近的資料中心
  • 資料同步:跨資料中心的資料複製,確保一致性
  • 測試與部署:自動化測試與部署工具,降低人為錯誤

10. 使用訊息佇列 (Message Queue) #

message-queue.png

隨著系統複雜度提升,應將服務拆分為獨立的元件 (Components)。

message-queue-2.png

非同步處理 #

訊息佇列讓服務間能非同步通訊

  • 生產者 (Producer):發布訊息到佇列
  • 消費者 (Consumer):從佇列取出訊息並處理

優勢 #

  • 解耦:生產者與消費者獨立運作
  • 擴展性:可根據佇列長度動態調整消費者數量
  • 容錯:訊息持久化,系統重啟後仍可處理

常用工具:RabbitMQ、Apache Kafka、Amazon SQS


11. 加上記錄、指標和自動化 (Logging, Metrics, Automation) #

大型系統需要完善的監控與自動化機制。

記錄 (Logging) #

  • 分級記錄(INFO、WARN、ERROR)
  • 集中式日誌管理(如 ELK Stack)
  • 幫助追蹤問題與除錯

指標 (Metrics) #

  • 主機層級:CPU、記憶體、硬碟 I/O
  • 應用層級:QPS、回應時間、錯誤率
  • 業務層級:使用者活躍度、轉換率

自動化 (Automation) #

  • CI/CD:持續整合與部署
  • 自動測試:單元測試、整合測試
  • 自動擴展:根據流量自動調整資源

logging-metrics-automation.png


12. 資料庫擴展 (Database Scaling) #

當單一資料庫無法負荷時,需要進行擴展。

database-scaling.png

垂直擴展 #

  • 升級硬體(CPU、RAM、SSD)
  • 受限於硬體極限,成本高昂

水平擴展 - 切片 (Sharding) #

  • 將資料分散到多個資料庫
  • 每個資料庫具有相同結構但儲存不同資料

分片策略

  • 範圍切片:依 ID 範圍(如 1-1000、1001-2000)
  • 雜湊切片:依 Hash 值分配
  • 地理切片:依地區分配

挑戰與解決方案 #

挑戰解決方案
單片過載重新調整切片函式,採用一致性雜湊 (Consistent Hashing)
熱門資料為熱門資料設置專屬切片或快取
JOIN 操作反正規化資料,或在應用層進行 JOIN
跨片交易採用分散式交易或最終一致性

總結 #

經過上述演進,系統架構已從單一伺服器成長為複雜的分散式系統。

conclusion.png

高流量系統設計通則 #

保持 Web 層無狀態
每層建立冗餘機制,避免單點故障
盡可能快取資料,減少資料庫壓力
支援多重資料中心,提升全球服務品質
使用 CDN 分發靜態資源
採用切片擴展資料層
拆分服務為獨立元件
監控系統並使用自動化工具


關鍵要點 #

擴展系統是一個持續迭代的過程,沒有完美的終點。根據業務需求與流量成長,不斷調整與優化架構,才能打造出穩定可靠的大規模系統。

從零到百萬使用者的旅程,就是一個不斷學習、優化、權衡取捨的過程。