Table of Contents
即時聊天系統架構:從需求到容量估算的全景筆記
本文整理自一支系統設計教學影片,加上我自己的筆記與延伸觀點。當作 reference 寫,之後面試或真的要設計即時通訊服務的時候,可以直接回來查。
一、從需求開始:聊天系統到底要解決什麼
聊到聊天系統,第一個反應就是「不就是訊息收發嗎?」但真要展開設計,需求面要先講清楚,否則後面的架構選擇會沒有依據。
Functional Requirements
- One-on-One Chat:一對一聊天是核心。
- Online Message Delivery:對方在線時,訊息要即時送到。
- Offline Message Delivery:對方離線,訊息要存起來等他上線讀。
- Group Chat:多人聊天,但建議限制人數(微信上限約 200 人,邀請制可到 500 人)。
- Presence Status:線上狀態顯示,像 QQ 那種頭像亮燈。
Non-Functional Requirements
- Scalability:假設 10 億使用者註冊(1 Billion Users)。
- Latency:低於 500ms,最好秒級內。
- High Consistency:雙方看到的訊息順序要一致;訊息不能丟。
- Fault Tolerance:不能隨便掛。
Multi-Device 是加分題,不是必答題。影片原話講得很直接:「主要的先解決,剩下的有時間再說。」
二、客戶端與伺服器的三種對話方式
這題我自己在準備面試時,常被問倒。因為一般設計 Twitter、Instagram 是「客戶端主動拉」,但聊天是「雙向推」。伺服器端要主動把訊息丟給客戶端,但網路層的 NAT 讓這件事變得麻煩。
1. Polling(輪詢)
最直覺:客戶端每隔幾秒問伺服器「有新訊息嗎?」
- 90% 的查詢是空的(浪費資源)
- 每次查詢都要重新建立 TCP 連線,三次握手成本高
- 優點:實作簡單,相容性 100%
- 缺點:伺服器負擔大、延遲高
2. Long Polling(長輪詢)
客戶端掛一個長連線在伺服器上,有訊息就回,沒訊息就 hold 著直到 timeout 再重連。
- HTTP-based,相容性好
- 需要管理連線的掛起、超時、喚醒邏輯
- 比 Polling 節省資源,但伺服器維護大量掛起連線也是成本
3. WebSocket
真正的雙向通訊,伺服器和客戶端都可以主動發訊息。
- 延遲最低、傳輸效率最高
- 但需要伺服器和客戶端都支援 WS 協定
- 舊瀏覽器相容性差
行動端的額外考量
手機 App 才是聊天系統的主戰場。Wi-Fi 切到 4G、基地台換了,IP 就變了,這時候 WebSocket 要重建連線。所以要引入 Client Token 來定位使用者,而不是用 IP。
更進階的選項是 QUIC(Google 提出),原生支援跨網路切換、阻塞控制。問題的時候可以 Fallback 回 WebSocket。
我的取捨建議:如果不是為了面試,現在新專案直接上 WebSocket + Client Token,行動端考慮 QUIC。Long Polling 留給必須相容舊瀏覽器的場景。
三、Session Register:在線狀態與路由基礎
定好通訊方式後,下一個問題是:訊息要送到哪台伺服器?
Heartbeat 機制
使用者登入時,會被分配到一台 Chat Server。客戶端每 10 秒發一次心跳(Heartbeat)。如果伺服器幾分鐘沒收到心跳,就視為離線。
存什麼
用一個 KV Store 存「會話註冊表」(Session Register):
| 欄位 | 範例 |
|---|---|
| User ID | u_12345 |
| Last Heartbeat | 1723891200 |
| Chat Server | chat-server-42 |
| Metadata | device type, app version |
容量估算
- 每條 Session 記錄約 100 bytes
- 10 億註冊 × 20% DAU × 25% 在線 = 5000 萬在線
- 5000 萬 × 100 bytes ≈ 5 GB
一般 KV Store 頂得住。
Presence 通知怎麼推
使用者狀態變化(上下線)時,可以推給他的線上好友。每個使用者在 Chat Server 上有一個「邏輯收件箱」,Presence 通知直接進收件箱。
這類通知對一致性要求不高——你晚幾秒收到「好友上線」的提醒,沒人會在意。
四、訊息投�架構:兩種主要路線
這一段是聊天系統設計的核心。有兩個完全不同的方向:把雙方湊到同一台機器,或讓訊息在機器間跑。
方案 A:Session Affinity(會話親和)
把正在聊天的兩個使用者,盡量遷到同一台 Chat Server。
- 優點:
- 訊息本機投遞,延遲最低
- 訊息排序簡單(用本地時鐘就好)
- 缺點:
- 使用者會在伺服器之間不停遷移,造成業務抖動
- 熱門使用者會造成 Hotspot(rehash、sharding 都得做)
適合:即時性要求極高的場景(例如多人遊戲房間內聊天)。規模小也適用。
方案 B:Message Sync(訊息同步)
每個使用者掛自己的 Chat Server,伺服器之間透過 RPC 或訊息佇列轉發。
- 優點:
- 水平擴容容易,使用者多就加機器
- 使用者不需遷移,直接連自己的 Chat Server
- 缺點:
- 多一層轉發,延遲高
- Session Register 必須精準(錯了就送不到)
- 雙端時鐘不同步,訊息順序問題複雜
優化:中心化 Pub/Sub Message Bus
如果你有 N 台 Chat Server,伺服器之間全互聯是 N² 條鏈路,太複雜。
更好的做法是引入一個中心化的 Pub/Sub 訊息匯流排:
- 訊息先寫到中心訊息佇列
- 接收方的 Chat Server 訂閱屬於自己的 topic
- 訊息一體化處理:持久化 + 排隊 + 轉發
- 持久化、訊息排隊、轉發整合在一起
- 鏈路複雜度降低(從 N² 變成中心 fan-out)
- Chat Server 可獨立彈性擴容
風險:中心化架構容易出 Hotspot。實務上要做 sharding、多佇列切分。
五、容量估算的具體數字
系統設計面試最容易被問倒的不是架構圖,而是「你的數字哪裡來的?」
訊息量
- 峰值在線:50M(5 千萬)
- 高峰時段:每 5 秒一條訊息 = 0.2 msg/sec/user
- 總訊息量:50M × 0.2 = 每秒 1000 萬條訊息
單訊息大小
| 欄位 | 大小 |
|---|---|
| Message ID | 8 bytes |
| From (User ID) | 8 bytes |
| To (User ID) | 8 bytes |
| Content(200-300 漢字 UTF-8) | 600-800 bytes |
| Timestamp | 8 bytes |
| 小計 | < 1 KB |
壓縮後約 0.5 KB/條。
總流量
10M msg/sec × 0.5 KB = 每秒 5 GB。
現代資料中心吃得下。
Chat Server 數量
兩種情境差很多:
- WhatsApp 等級(單機 200 萬並發):50M ÷ 2M = 25 台就夠
- 普通機器(單機 5 萬並發):50M ÷ 50K = 1000 台
WhatsApp 2012 年的技術部落格講過,他們單機能撐 200 萬連線,用的是 Erlang + Actor 模型,這是特例不是常態。
地理親和的假設
聊天對象大概率是身邊的人(同事、家人、朋友),地理相近會被分到同一個資料中心。
- 同機率假設 20%
- 80% 訊息走跨服轉發
單機轉發量估算:
2M users × 0.2 msg/sec × 0.5 KB × 80% 轉發 = 每台 160 MB/s
加上雙向(1-1 chat 兩邊都要送),約 320 MB/s。
普通機器或 Kafka 都能扛。如果走 Kafka,10 台 broker 處理 5 GB/s 完全沒問題。
六、群聊、離線訊息與隱私
群聊實作
群聊訊息 Schema 和一對一類似:
group_id | message_id | user_id | content | timestamp
約 0.5 KB/條
需要一個 Group Registration,記錄每個群成員分散在哪些 Chat Server。
範例:500 人群分散在 10 台 Chat Server → 訊息要複製 10 份跨服。但伺服器內部可以用同機路由減少跨服開銷。
離線訊息
對方不線上時,訊息進 Offline Storage:
- 2 億 DAU × 每天 40 條 × 15% 離線 × 0.5 KB = 0.6 TB/day
- 保留 30 天 ≈ 18 TB
實作選擇:
- 簡單場景:檔案系統,每個使用者一個資料夾,log file append-only
- 高吞吐:NoSQL / KV Store,水平擴容友善
離線訊息對延遲不敏感,技術選型可以保守。
隱私 vs 資料安全
影片最後一段我覺得蠻有意思的:
「如果不是很必要,我們應該盡可能少保存聊天資料。一旦 message deliver 後就從記憶體刪掉,既保護使用者,又降低洩漏風險,同時降低系統複雜度。」
企業用的 IM(Slack、Teams)需要長期保存聊天記錄沒問題,但面向一般消費者的產品,這個權衡要重新思考。GDPR、隱私法規、使用者信任——這些都不是技術問題,但會影響你的架構選擇。
結語
聊天系統架構沒有「標準答案」。每一個選擇都是延遲、複雜度、可靠性的三角權衡。
WhatsApp 用 Actor 模型 + Erlang 做到單機 200 萬並發,這是特例不是常態。大部分團隊會落在「中心化訊息佇列 + 多 Chat Server 轉發」的甜蜜點,並靠 sharding 和多佇列切分避免中心瓶頸。
面試時把 trade-off 講清楚,比背架構圖更重要。數字記得有把握(5 GB/s、25 台、200 萬連線),這是基本功。
之後如果要真正實作,重點會落在三件事:
- 訊息順序保證(單調遞序 ID vs 邏輯時鐘)
- 訊息投遞保證(ack、重試、exactly-once 語意)
- 離線訊息同步(增量同步、last-read cursor、conflict resolution)
這幾個題目之後再寫一篇。
參考資料:
- YouTube 影片:「Design a Chat System」系統設計教學
- WhatsApp Engineering Blog(2012 單機 200 萬連線案例)
- C10M Challenge(單機 1000 萬並發連線目標)