連線自癒機制:打造打不倒的 WebSocket 連線
在分散式系統與不穩定的網路環境(特別是移動裝置)中,連線中斷是「常態」而非例外。如果你的 WebSocket 連線斷了就沒了,使用者體驗會非常糟糕。
本章我們將探討如何讓連線具備「自癒能力」,透過 狀態機 (State Machine) 追蹤狀態,並使用 指數退避 (Exponential Backoff) 策略優雅地重連。
一、 狀態機 (State Machine) 架構
一個穩健的 WebSocket 客戶端不應該只是簡單的連線,它應該在不同狀態間明確切換。
二、 實戰演練:具備自癒能力的客戶端封裝
關鍵演算法:指數退避 (Exponential Backoff)
如果連線失敗,我們不應該立刻重連,而是逐次增加等待時間: delay = min(baseDelay * (2 ^ attempts), maxDelay)
JavaScript 實作
javascript
class ResilientWebSocket {
constructor(url, options = {}) {
this.url = url;
this.options = Object.assign(
{
baseDelay: 1000,
maxDelay: 30000,
},
options
);
this.attempts = 0;
this.ws = null;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => (this.attempts = 0);
this.ws.onclose = () => this.reconnect();
}
reconnect() {
const delay = Math.min(
this.options.baseDelay * Math.pow(2, this.attempts),
this.options.maxDelay
);
setTimeout(() => {
this.attempts++;
this.connect();
}, delay);
}
}三、 陷阱提醒:驚群效應 (Thundering Herd)
當伺服器大規模重啟時,所有客戶端若同時使用相同的退避公式重連,會瞬間殺死剛啟動的伺服器。
解決方案:加入抖動 (Jitter) 在計算好的延遲中加入一個隨機值: delay = calculatedDelay + Math.random() * 1000
總結
透過智慧的重連機制,我們能將「短暫的斷線」對使用者的影響降到最低,建立穩定且可靠的實時體驗。
下一章,我們將探討架構設計模式:建立生產級的訂閱/發布架構。
️ 進階挑戰
- 實作挑戰:將上面的
ResilientWebSocket加入「心跳機制 (Heartbeat)」,如果伺服器超過 10 秒沒發送 Ping,主動判定為斷線並啟動重連。 - 架構思考:在重連期間,如果使用者發送了訊息,你應該「直接捨棄」還是「存入隊列 (Queue) 等連線恢復後發送」?這兩種做法分別適合什麼場景?
延伸閱讀與資源
- AWS Architecture Blog:Exponential Backoff and Jitter
- Wiki:Finite-state machine