一對一與小型群組聊天的後端:client 各自連上聊天服務,由它收訊、找到接收者、轉發,或在對方離線時暫存。難點在伺服器主動推訊息、訊息順序與持久連線的管理。
📋 Requirements
- 功能:低延遲一對一聊天、最多 100 人的小型群組聊天、線上狀態、多裝置支援、推播通知;只支援文字訊息(長度 < 100,000 字元)。
- 規模:5,000 萬 DAU;聊天紀錄永久保存。
- 資料量龐大但只有最近的聊天常被存取;一對一聊天讀寫比約 1。
🧠 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
- 傳送端 HTTP 就夠,接收端要伺服器主動推——WebSocket(雙向、持久)勝過 polling / long polling。
- 持久連線讓聊天服務有狀態,因此需要服務發現協調、避免伺服器超載,並在伺服器離線時給 client 新伺服器。
- 訊息順序靠可時間排序的唯一 message ID,不是時間戳;群組用
(channel_id, message_id)。 - 聊天紀錄選 key-value store(水平擴展、低延遲);小群組用「複製到各收件匣」的 message sync queue 簡化同步。
- 線上狀態用心跳判定、發布-訂閱 fanout;大群組要避免對所有成員廣播狀態。
No notes yet — jot your takeaways or Q&A here.