設計聊天系統 (Chat System)

Hard★★★★★Draft

FromSystem Design Interview

Concepts practiced🔌 即時更新:Long-Polling / WebSocket / SSE📨 訊息佇列 (Message Queue)📈 負載均衡 (Load Balancing)

Convention: read the requirements & constraints first, sketch your own design, then expand the reference to compare.

📚 From the Books

設計聊天系統 (Chat System)ProblemHardSocial & Feed

一對一與小型群組聊天的後端:client 各自連上聊天服務,由它收訊、找到接收者、轉發,或在對方離線時暫存。難點在伺服器主動推訊息訊息順序持久連線的管理

📋 Requirements

🧠 Core Ideas

TIP

Client 之間不直接通訊,全部連到聊天服務。傳送端用 HTTP 即可(keep-alive 維持持久連線),但接收端要伺服器主動推——這才是關鍵。

伺服器主動推訊息有三種技術:polling(定期問「有沒有新訊息」,多數時候答案是沒有,浪費資源)、long polling(連線開著直到有訊息或逾時;缺點是無狀態 HTTP 伺服器下傳送者與接收者可能不在同台、伺服器難判斷斷線)、以及 WebSocket——由 client 發起、雙向、持久,從 HTTP handshake 升級而來,成為即時更新的主要方案。

WebSocket 只用於即時訊息;註冊、登入、使用者資料等仍走傳統 HTTP request/response。

⚖️ Reference Design

三類元件
  • 無狀態服務:登入、註冊、使用者資料等 request/response 服務,置於 load balancer 之後依路徑路由。
  • 有狀態服務:唯一的有狀態服務是聊天服務——每個 client 與一台聊天伺服器維持持久連線,通常不切換。
  • 第三方整合:推播通知,在 App 未執行時仍能通知新訊息。

高階元件包含聊天伺服器(收發訊息)、presence 伺服器(在線/離線狀態)、API 伺服器(登入註冊等)、通知伺服器、以及存聊天紀錄的 key-value store。單機理論上塞得下(100 萬並行連線 × 10K ≈ 10GB),但單點故障是致命缺陷。

儲存與 message ID
  • 通用資料(個人資料、設定、好友清單)放關聯式資料庫,靠 replication 與 sharding。
  • 聊天紀錄放 key-value store:易水平擴展、低延遲;關聯式資料庫在索引變大時對長尾資料的隨機存取成本高。
  • 一對一訊息表 primary key 是 message_id(決定順序);群組用複合 key (channel_id, message_id)channel_id 當 partition key。
  • 不能用 created_at 排序(同時建立會撞);message_id 需唯一且可依時間排序,可用全域 64-bit 序號產生器(如 Snowflake),或只在 channel 內唯一的區域序號產生器。
訊息流與服務發現
  • 服務發現(如 Apache Zookeeper)依地理位置、伺服器容量為 client 挑最佳聊天伺服器:登入驗證後回傳伺服器資訊,client 再用 WebSocket 連上。
  • 一對一流程:聊天 server 1 取得 message ID → 送進 message sync queue → 存 KV store → 接收者在線就轉發到其所在的 server 2,離線則發推播。
  • 多裝置同步:每台裝置維護 cur_max_message_id;接收者 ID 相符且 KV store 中 message ID 更大者即為新訊息,各裝置各自拉取。
  • 小型群組:傳送者的訊息複製到每位成員的 message sync queue(收件匣),client 只需檢查自己的收件匣。成員少時複製副本不貴;大群組則不可接受。
線上狀態 (Presence)
  • 登入後在 KV store 記錄在線狀態與 last_active_at;登出則改為離線。
  • 心跳機制處理斷線:client 定期送 heartbeat,presence 伺服器在 x 秒內收到才算在線。避免使用者頻繁斷/重連(如過隧道)造成狀態抖動。
  • 狀態 fanout 用發布-訂閱:每對好友一個 channel,狀態變更時發布給訂閱者。大群組(如 10 萬人)會產生等量事件,改為進群或手動重整時才抓取。

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading