即時更新 (Real-time Updates)

核心問題

標準 HTTP 是請求-回應模型:client 要、server 回、連線關閉。但即時應用(Google Docs、聊天)需要 server 主動推送給 client,且不能讓每個 client 每幾毫秒輪詢一次(會打垮基礎設施)。

即時系統要解決兩個截然不同的問題(Two Hop)

  • 第一個 Hop:如何把更新從 server 送達 client?(通訊協定)
  • 第二個 Hop:如何把更新從 事件來源傳播到 server?(觸發機制)


第一個 Hop:Client-Server 通訊協定

協定 方向 底層 延遲 何時用
Simple Polling client 拉 HTTP 高(間隔) 不在意延遲的基準方案
Long Polling client 拉(掛起) HTTP 近即時、低頻、偏好簡單
SSE server → client HTTP(chunked) 單向推送(AI token 串流、儀表板)
WebSocket 雙向 TCP(HTTP upgrade) 最低 高頻雙向(聊天、遊戲)
WebRTC P2P UDP 最低 音視訊通話、P2P 資料
不在意延遲          → Simple Polling(最簡單基準)
不需雙向            → SSE(輕量,適合大多數推送)
需要高頻雙向        → WebSocket(複雜但效能最強)
需要音視訊通話      → WebRTC(唯一適合)
大多數人過度急著用 WebSocket

寫入永遠可以另發 HTTP 請求 —— 常見模式是 SSE 訂閱更新 + 一般 HTTP POST 寫入。除非確實需要雙向,先考慮 SSE。詳見 01-Networking/05-Realtime-Protocols

各協定要點

L4 vs L7 LB 對 WebSocket 的影響

L7 LB 終止連線再建新連線,破壞 WebSocket 持久連線 → WebSocket 必須用 L4 LB(同一條 TCP)。Long polling 等 HTTP 方案 L7 更靈活。詳見 01-Networking/06-Load-Balancing


第二個 Hop:Server 端更新傳播

系統不斷產生需推送的更新(他人的編輯、司機位置、聊天訊息)。三種觸發模式:

1. 拉取:Simple Polling

client 不斷向 server 請求,server 用 DB 維護狀態回應。美妙在解耦(DB 橫亙在生產者/消費者之間),代價是失去即時性。

大量 client 時容易忘記算

一百萬 client 每 10 秒輪詢一次 = 每秒 10 萬次讀取

2. 推送:Consistent Hashing

持久連線需要 client 和某台 server 保持連線 → 要知道「用戶 C 連到哪台 server」。

ZooKeeper / etcd 管理 server 分配。適合需維護大量關聯狀態的持久連線(如 Google Docs,連線和特定文件關聯)。詳見 02-Distributed-Systems/04-Consistent-Hashing

3. 推送:Pub/Sub(廣播首選)

專門服務(Kafka / Redis)收集來源更新,廣播給訂閱者。持久連線連到輕量「端點伺服器」,後者訂閱相關 topic 並轉發。

更新來源 ──► Pub/Sub (topic) ──廣播──► 端點伺服器們 ──► 各自的 client 連線
Consistent Hashing vs Pub/Sub 怎麼選

連線需維護大量狀態(協作編輯)→ Consistent Hashing;只傳小訊息、無太多關聯狀態(聊天通知)→ Pub/Sub。


常見 Deep Dive


常見系統範例

系統 協定 + 傳播
聊天 WebSocket(雙向)+ Pub/Sub 分發;考慮排序、typing indicator、presence
直播留言 極端 fan-out → 階層式聚合 + 批次處理
協作編輯 WebSocket + OT / CRDT 處理衝突;游標/選取高亮增加複雜度
即時儀表板 SSE(單向)+ 注意聚合間隔
多人遊戲 WebRTC(P2P 降延遲)+ WebSocket(server 協調)

何時不用

能用 Simple Polling 解就別引入即時更新

不在意延遲時,輪詢是極佳基準,複雜度最低(Senior+ 面試非常欣賞)。用輪詢可同時迴避兩個 hop。大多數候選人過度設計即時方案。