Scale From Zero To Millions Of Users #
本章探討系統如何從最簡單的單一伺服器架構,逐步演進到能支援百萬級使用者的分散式系統。
1. 設置單一伺服器 (Single Server) #
最簡單的 Web 應用架構只需要一台伺服器,包含 Web Server、應用程式和資料庫。

運作流程:
- 使用者透過網域名稱 (Domain Name) 向 DNS 查詢目標網站的 IP 位址
- DNS 回傳 IP 位址 (Internet Protocol)
- 瀏覽器向此 IP 發送 HTTP 請求 (Hypertext Transfer Protocol)
- 伺服器處理請求並回傳 HTML,瀏覽器渲染出網頁
適用場景:小型應用、MVP、個人專案
2. 獨立出資料庫 (Database) #
隨著使用者增加,將資料庫從 Web Server 分離能提升效能與可擴展性。
資料庫選擇 #

關聯式資料庫 (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) #

採用水平擴展後,需要負載平衡器來分配流量。
運作原理 #
- 負載平衡器作為使用者與伺服器之間的橋樑
- 伺服器使用私有 IP 互相通訊(不對外公開)
- 使用者只知道負載平衡器的公開 IP
帶來的好處 #
- 流量分散:避免單一伺服器過載
- 高可用性:某台伺服器下線時,流量自動轉向其他伺服器
- 彈性部署:可輕鬆增減伺服器數量
5. 備份資料庫 (Database Replication) #

資料庫也需要容錯機制,常見做法是採用主從架構 (Master-Slave)。
主從架構 #
- 主資料庫 (Master):處理寫入操作(INSERT、UPDATE、DELETE)
- 從資料庫 (Slave):處理讀取操作,並同步主資料庫的資料
優勢 #
- 效能提升:讀寫分離,提高並行處理能力
- 可靠性:即使某個從資料庫損壞,資料仍可從其他副本取得
- 高可用性:某台資料庫下線,其他資料庫仍可運作
故障處理 #
從資料庫下線:
- 若只有一台從資料庫,讀取請求暫時導向主資料庫
- 盡快部署新的從資料庫
主資料庫下線:
- 提升一台從資料庫為新的主資料庫
- 使用資料恢復腳本找回可能遺失的資料
- 考慮採用多主架構或自動容錯轉移機制

6. 導入快取 (Cache) #

快取將常用資料存入記憶體,大幅減少資料庫查詢次數。
運作流程 #
- 伺服器收到請求,先檢查快取
- 快取命中 (Cache Hit):直接回傳資料
- 快取未命中 (Cache Miss):從資料庫查詢,並寫入快取
設計考量 #
| 考量點 | 說明 |
|---|---|
| 適用資料 | 常被存取且較少更動的資料 |
| 過期時間 (TTL) | 不宜過短(效益低)或過長(資料可能過時) |
| 資料一致性 | 確保快取與資料庫資料同步 |
| 避免單點故障 | 使用多個快取節點(如 Redis Cluster) |
| 驅逐政策 | 當容量不足時,採用 LRU、LFU 或 FIFO 策略 |
常用快取解決方案:Redis、Memcached
7. 設置 CDN (Content Delivery Network) #

CDN 用於快速分發靜態內容(圖片、影片、CSS、JavaScript)。
運作原理 #
- 將靜態資源部署到全球各地的邊緣節點
- 使用者從最近的節點取得資源,降低延遲
設計考量 #
- 成本評估:CDN 服務需付費,評估使用頻率是否划算
- 設定過期時間:確保內容適時更新
- 備援機制:CDN 故障時,伺服器能作為備案
- 版本管理:透過 URL 加上版本號(如
style.v2.css)控制更新 - 內容失效:使用 CDN 供應商的 API 清除過時內容

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

為了實現水平擴展,Web Server 必須是無狀態的。
有狀態 vs 無狀態 #
有狀態 (Stateful):
- Session 資料存在伺服器記憶體中
- 使用者請求必須路由到同一台伺服器
- 限制了負載平衡的彈性
無狀態 (Stateless):
- Session 資料存在共享儲存(如 Redis、資料庫)
- 任何伺服器都能處理任何請求
- 易於擴展與部署
9. 建置資料中心 (Data Centers) #

為了服務全球使用者,需要在不同地理位置建立多個資料中心。
優勢 #
- 降低延遲:使用者連接到最近的資料中心
- 高可用性:某個資料中心故障,流量轉移到其他資料中心
實作要點 #
- GeoDNS 路由:根據使用者地理位置導向最近的資料中心
- 資料同步:跨資料中心的資料複製,確保一致性
- 測試與部署:自動化測試與部署工具,降低人為錯誤
10. 使用訊息佇列 (Message Queue) #

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

非同步處理 #
訊息佇列讓服務間能非同步通訊:
- 生產者 (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:持續整合與部署
- 自動測試:單元測試、整合測試
- 自動擴展:根據流量自動調整資源

12. 資料庫擴展 (Database Scaling) #
當單一資料庫無法負荷時,需要進行擴展。

垂直擴展 #
- 升級硬體(CPU、RAM、SSD)
- 受限於硬體極限,成本高昂
水平擴展 - 切片 (Sharding) #
- 將資料分散到多個資料庫
- 每個資料庫具有相同結構但儲存不同資料
分片策略:
- 範圍切片:依 ID 範圍(如 1-1000、1001-2000)
- 雜湊切片:依 Hash 值分配
- 地理切片:依地區分配
挑戰與解決方案 #
| 挑戰 | 解決方案 |
|---|---|
| 單片過載 | 重新調整切片函式,採用一致性雜湊 (Consistent Hashing) |
| 熱門資料 | 為熱門資料設置專屬切片或快取 |
| JOIN 操作 | 反正規化資料,或在應用層進行 JOIN |
| 跨片交易 | 採用分散式交易或最終一致性 |
總結 #
經過上述演進,系統架構已從單一伺服器成長為複雜的分散式系統。

高流量系統設計通則 #
✅ 保持 Web 層無狀態
✅ 每層建立冗餘機制,避免單點故障
✅ 盡可能快取資料,減少資料庫壓力
✅ 支援多重資料中心,提升全球服務品質
✅ 使用 CDN 分發靜態資源
✅ 採用切片擴展資料層
✅ 拆分服務為獨立元件
✅ 監控系統並使用自動化工具
關鍵要點 #
擴展系統是一個持續迭代的過程,沒有完美的終點。根據業務需求與流量成長,不斷調整與優化架構,才能打造出穩定可靠的大規模系統。
從零到百萬使用者的旅程,就是一個不斷學習、優化、權衡取捨的過程。