跳至主要內容
Skip to content

連線自癒機制:打造打不倒的 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


總結

透過智慧的重連機制,我們能將「短暫的斷線」對使用者的影響降到最低,建立穩定且可靠的實時體驗。

下一章,我們將探討架構設計模式:建立生產級的訂閱/發布架構。


️ 進階挑戰

  1. 實作挑戰:將上面的 ResilientWebSocket 加入「心跳機制 (Heartbeat)」,如果伺服器超過 10 秒沒發送 Ping,主動判定為斷線並啟動重連。
  2. 架構思考:在重連期間,如果使用者發送了訊息,你應該「直接捨棄」還是「存入隊列 (Queue) 等連線恢復後發送」?這兩種做法分別適合什麼場景?

延伸閱讀與資源