WebSocket 擴展:垂直 vs 水平、load balancer 與 backplane

文字解析 · 1 支影片 · 產生於 2026-10-01 00:54

🎧 語音解析📝 筆記✍️ 練習

🎧 語音解析 16m10s · TTS 講解與作者原聲交錯;點章節可跳。
邊聽邊看逐句講稿,點任一句從那裡開始
章節(8)

1. Outline

  1. 起點 · How to scale WebSockets to millions of connections
    從「WebSocket 為何難擴展」出發,先拆掉 benchmark 迷思,再比較垂直與水平擴展,最後用 Redis backplane 解決多台伺服器狀態分裂,並列出水平擴展自己的挑戰。

2. YouTuber 的思維推導

How to scale WebSockets to millions of connections

Ably Realtime · 14m00s · 字幕 en · vision=on (input 指定 vision=true。影片是動畫講解型,架構圖(load balancer、server 1/2、Redis backplane)與清單畫面是理解水平擴展問題的關鍵。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 2s
segment 58s 2m30s
shot 39s 9s
analyze 6m15s 7m20s
render 5s –

作者(Ably 的 Alex)從一個觀察出發:很多人在問「WebSocket 要怎麼擴展」,而這個問題之所以難,是因為 WebSocket 是有狀態、長時間存活的連線,伺服器得為每條連線持續綁定 memory 與 CPU,跟 HTTP 短連線、無狀態的性質正好相反,連線一多就會撞硬體上限,而且往往剛好發生在產品起飛時。他先清掉兩個前提:網路上「原生 WebSocket 撐百萬連線」的 benchmark 不可信,因為上線要多做 heartbeat、buffering 等工作;而且還得準備 HTTP long polling 這類 fallback,它的擴展方式又完全不同。接著他把後端擴展拆成兩條路——垂直(加大一台)與水平(加多台 + load balancer)——並先檢驗最誘人的那條:如果「一台能撐多少」的數字夠大,垂直擴展就最省事。

但他的結論是這個數字沒有答案,而且就算夠大,垂直擴展仍有四個實務問題:貴、終究撞資源限制、單點故障讓部署變得綁手綁腳、程式錯誤或雲端區域故障會讓整個服務下線。既然單機的根本問題是「只有一個故障點」,他轉向水平擴展:多台機器可動態增減、一台掛了別台接手,load balancer 用 round robin 之類的演算法分流。但他隨即用一張圖揭露水平擴展的代價:連線被分到不同伺服器後,狀態就碎了——server 2 不知道 server 1 上發生什麼,聊天訊息送不到、廣播也拿不到完整連線清單。

解法是把連線狀態放到 process 之外,用 Redis pub/sub 這類 message broker 當 backplane,讓所有伺服器共享同步的狀態視圖。然後他誠實地列出水平擴展自己的挑戰:資料與連線狀態的同步、Redis 變成新的單點故障要複製、單台逼近上限時要做 load shedding、以及被踢或掛機後大量連線同時湧回的 thundering herd。最後回到起點的問題:「一台能撐多少」本身就問錯了,因為連線各不相同,而且單機終究是單點故障;水平擴展是可靠、高擴展性後端的關鍵,但複雜度要自己承擔。

他不下定論——能接受停機風險就一台垂直擴展的伺服器也行,金融這類不能停的服務則值得一開始就投資水平擴展。

推理鏈:每段留給下一段的線索

每一列是一段,箭頭後的字是這段留給下一段的線索。點段落標題跳到該段。

  1. 為什麼 WebSocket 難以擴展 → 作者說「我們先看擴展 WebSocket 的挑戰」——但在講怎麼擴展之前,他要先處理一個常見的錯誤參照:網路上那些「原生 WebSocket 撐百萬連線」的 benchmark,為什麼不能拿來當你的容量規劃依據?
  2. 為什麼 WebSocket benchmark 會誤導 → 把通用成本清掉之後,作者說「來看你擴展 WebSocket 的選項」——後端擴展到底有哪幾條路?而其中最直覺的那條(把一台機器加大)能不能直接解決問題?
  3. 兩種擴展方式與「一台能撐多少」 → 作者話鋒一轉:「就算那個數字真的很高」,垂直擴展還有一些實務上的考量要知道——他整理了一份小清單,那些問題是什麼?
  4. 垂直擴展的實務問題 → 單機的根本問題是「只有一個故障點」——作者說「也許水平擴展能解決其中一些問題,來仔細看看」:多台機器怎麼分流?分流之後又是誰在指揮?
  5. 水平擴展與 load balancer → 作者說「不幸的是,沒那麼簡單」、「水平擴展最大的缺點是它引入的架構複雜度」——具體是什麼複雜度?他準備了一張圖來說明。
  6. 狀態分裂與 backplane → 作者反問:「所以水平擴展是魔法銀彈嗎?完全不是」——加了 backplane 之後,水平擴展自己又帶來哪些挑戰?
  7. 水平擴展的挑戰 → 所有問題都能解、但都要付出複雜度——那到底該不該走水平擴展?作者回到影片一開始那個問題「一台能撐多少連線」,準備給出他的最終看法。
  8. 結論:依需求選擇

3. 逐段說明

How to scale WebSockets to millions of connections

1. 為什麼 WebSocket 難以擴展 0:00–1:32

作者先點出核心矛盾:WebSocket 是有狀態、長連線的協定,伺服器要為每條連線持續占用 memory 與 CPU,這和 HTTP 短連線、無狀態、容易擴展的性質相反。連線數一多,伺服器就會撞到硬體上限,而且通常剛好發生在產品開始起飛的時候。這支影片不是教學,而是整理擴展到數千到數百萬連線的通用做法與模式。

stateful 長連線 vs stateless HTTP 的對照畫面,是整支影片的出發點。
0:30 · stateful 長連線 vs stateless HTTP 的對照畫面,是整支影片的出發點。
承上 用上「前情提要」裡的兩個背景:WebSocket 是先用一次 HTTP handshake 升級、之後保持一條雙向連線的協定;而 HTTP 是每次 request/response 完就結束的協定。作者假設觀眾已經懂 WebSocket 怎麼運作,直接從這個對比切入。

推理因為作者觀察到很多人在問「WebSocket 怎麼擴展」,所以他先回答「為什麼這個問題值得問」:WebSocket 跑在一條 stateful、長時間存活的連線上,伺服器要為它持續綁定 memory 和 CPU,期限不定;HTTP 則是 stateless、連線短暫,短期對伺服器負擔輕、長期也好擴展。所以只要連線數多(或預期會多),單台伺服器就會撞到硬體上限,出現效能與穩定性問題——而這通常剛好發生在產品開始有人用的時候。作者由此定下影片的範圍:不是逐步教學、不綁特定技術,而是整理把 WebSocket 擴展到數千、數萬、數十萬甚至百萬連線的通用做法與模式。

AI 補充截圖(30 秒)左邊是 WebSocket:先一來一回的「Initial HTTP handshake」,之後同一條線上 full-duplex、persistent 地雙向傳訊,直到雙方 Close;右邊是 HTTP request-response cycle:Request 1 / Response 1、Request 2 / Response 2 各自獨立。作者說 WebSocket「stateful」時指的不只是 TCP 連線一直開著,還包括伺服器記憶體裡必須為每條連線保留 socket buffer、這個 client 是誰、訂閱了什麼等資訊——這些是 HTTP 每次請求做完就能丟掉的。他沒明說但推理上需要的一步:正因為狀態綁在「某一台伺服器的記憶體」,後面任何把負載搬到別台的做法都得先處理這些狀態要放哪,這是整支影片真正的主軸。

WebSocket

WebSocket 協定

一種在單一 TCP 連線上提供全雙工、持續通訊的協定,由一次 HTTP handshake 升級而來。

瀏覽器先送一個帶 Upgrade: websocket 的 HTTP 請求,伺服器回 101 Switching Protocols 之後,同一條 TCP 連線就改跑 WebSocket frame,雙方可以隨時互相推送訊息,不需要客戶端一直輪詢。它的 API 很精簡(open / message / close),所以本身效率高,但也表示重連、心跳、訊息確認這些都要自己做。常見誤解是把它當成「快一點的 HTTP」;本質差異在於連線是長期存在且有狀態的。

相關術語: stateful (屬性)、full-duplex (屬性)

出處:第 1 段「為什麼 WebSocket 難以擴展」

stateful

有狀態的

伺服器必須在連線存續期間持續保存與該連線相關的資訊(記憶體、buffer、身分、訂閱)。

「狀態」在這裡不是抽象概念,而是實際占用的資源:每條 WebSocket 連線在伺服器上至少有一個 socket、對應的讀寫 buffer,以及應用層記錄的 client 資料。連線不斷、狀態就不能釋放,所以連線數直接對應記憶體與 CPU 的常駐用量。這和 stateless 相反,也是 WebSocket 擴展困難的根源。

相關術語: stateless (相反)

出處:第 1 段「為什麼 WebSocket 難以擴展」

stateless

無狀態的

每次請求自帶所需的全部資訊,伺服器處理完不必記住任何事。

HTTP 的 request-response 模型就是典型:請求進來、回應出去、連線(或至少這次交易)結束,伺服器可以立刻釋放資源。因為任一台伺服器都能處理任一個請求,把請求分散到多台機器非常容易,這就是作者說 HTTP「長期更好擴展」的原因。注意 HTTP/1.1 keep-alive 或 HTTP/2 雖然會重用 TCP 連線,但應用層仍是無狀態的。

相關術語: stateful (相反)

出處:第 1 段「為什麼 WebSocket 難以擴展」

full-duplex

全雙工

連線兩端可以同時、獨立地互相傳送資料,不必等對方先開口。

截圖上 WebSocket 那條線標的就是 full-duplex persistent。HTTP 是半雙工的一問一答:伺服器不能主動推資料給客戶端。全雙工讓伺服器能即時推送,這是即時應用選 WebSocket 的理由,但也表示伺服器得隨時為每條連線保持可寫的通道,進一步加深了有狀態的性質。

相關術語: WebSocket (特性之一)

出處:第 1 段「為什麼 WebSocket 難以擴展」

留給下一段 作者說「我們先看擴展 WebSocket 的挑戰」——但在講怎麼擴展之前,他要先處理一個常見的錯誤參照:網路上那些「原生 WebSocket 撐百萬連線」的 benchmark,為什麼不能拿來當你的容量規劃依據?

2. 為什麼 WebSocket benchmark 會誤導 1:32–3:03

網路上常見「原生 WebSocket 撐到百萬連線」的 benchmark,但那不切實際:上線後還要做 heartbeat、buffering、未送達訊息處理等額外工作,讓 WebSocket 比 benchmark 看起來更吃資源。另外還要準備 HTTP long polling 這種 fallback transport,以應付防火牆或錯誤設定的 proxy 擋掉 WebSocket 的情況;long polling 相容性高但效率低,而且擴展方式跟 WebSocket 完全不同,複雜度再加一層。

畫面列出上線 WebSocket 必須額外做的事(heartbeat、buffering 等),是說明 benchmark 為何失真的依據。
2:05 · 畫面列出上線 WebSocket 必須額外做的事(heartbeat、buffering 等),是說明 benchmark 為何失真的依據。
承上 承上:作者要先拆掉「原生 WebSocket 撐百萬連線」這個常見參照,才能談真正的擴展。他先確認觀眾已懂 WebSocket 怎麼運作與適用場景,然後點出 WebSocket API 極簡、預設效率高——這正是 benchmark 好看的原因。

推理因為上一段確立了 WebSocket 是有狀態的長連線、資源會隨連線數常駐,所以作者接著檢查「一條連線到底占多少」——而網路 benchmark 給的數字太樂觀。原因是 benchmark 跑的是「原生」WebSocket,但要上線就得額外做 heartbeat、buffer 未送達的訊息等處理,這些讓每條連線比 benchmark 更吃資源。第二個常被忽略的成本是 fallback:防火牆或設定錯誤的 proxy 可能擋掉 WebSocket,你得準備 HTTP long polling 這類替代 transport;它相容性極高但效率很差,對伺服器更吃力,而且擴展 long polling 的方式跟擴展 WebSocket 完全不同,複雜度又多一層。作者把這兩點定位為「不管用哪種方法擴展都會遇到」的通用成本,清掉之後才進入擴展選項。

AI 補充截圖(125 秒)標題「WebSockets — Batteries not included!」列出了作者只念了兩項的完整清單:Heartbeat、Buffer undelivered messages、Message routing、Broadcast、Handling backpressure、Automatic reconnection、Message acknowledgements、Encryption、Multiplexing。這九項就是「原生 WebSocket 沒附的電池」,每一項都會在每條連線上加記憶體或 CPU:heartbeat 要為每條連線排 timer;buffer 要為離線的 client 暫存訊息;backpressure 要為慢的 client 保留佇列。所以「百萬連線」的 benchmark 量的其實是空連線的上限,不是有業務邏輯的連線。關於 fallback,作者沒解釋「為什麼擴展方式完全不同」:long polling 是一連串短命的 HTTP 請求,每次請求可能落到不同伺服器,所以它的「一條連線」其實是散在多台機器上的多個請求——這正好是第 1 段說的 stateless 特性,需要用 HTTP 那套(無狀態、靠 session id 找回上下文)來擴展,跟 WebSocket 一條長連線固定在一台伺服器的模型是兩套邏輯。

heartbeat

心跳

定期在連線上互送小訊息,確認對方還活著並防止中間設備因閒置切斷連線。

WebSocket 協定有 ping/pong control frame,但何時送、多久沒回應算斷線,都要應用自己決定並實作。沒有 heartbeat 時,NAT 或 proxy 可能在幾十秒閒置後默默丟掉連線,伺服器卻仍以為連線存在、繼續為它保留狀態(第 1 段講的 stateful 資源)。每條連線一個 timer,是 benchmark 通常不算的成本。

相關術語: stateful (維護其正確性)

出處:第 2 段「為什麼 WebSocket benchmark 會誤導」

buffering

訊息緩衝

把暫時送不出去(對方離線或還沒重連)的訊息暫存起來,等連線恢復再補送。

原生 WebSocket 送出去就送出去了,斷線期間的訊息會直接遺失。要保證「離線期間的訊息回來還看得到」,伺服器得為每個 client 保留一段訊息佇列,這是額外的記憶體,而且要決定留多久、留多少。這也是為什麼「有業務邏輯的連線」比空連線貴。

相關術語: backpressure (同屬佇列管理)

出處:第 2 段「為什麼 WebSocket benchmark 會誤導」

backpressure

背壓

當接收方消化速度跟不上發送方時,讓發送方減速或暫停,避免佇列無限增長。

截圖清單裡的「Handling backpressure」。如果某個 client 網路很慢,伺服器一直往它的 socket 寫,寫不出去的資料會堆在 buffer 裡吃記憶體,最終拖垮整台伺服器。處理方式包括檢查 bufferedAmount、暫停產生訊息、或乾脆斷掉太慢的 client。這是原生 API 不會替你做的事。

相關術語: buffering (控制其上限)

出處:第 2 段「為什麼 WebSocket benchmark 會誤導」

fallback transport

備援傳輸方式

WebSocket 連不上時改用的替代通訊方式,讓功能在受限網路下仍能運作。

企業防火牆、舊的或設定錯誤的 proxy 可能不認得 Upgrade 請求而擋掉 WebSocket。為了不讓這些使用者完全不能用,服務要能自動退到另一種 transport(HTTP long polling、SSE 等)。代價是你得同時維護與擴展兩套通訊模型。

相關術語: HTTP long polling (一種)

出處:第 2 段「為什麼 WebSocket benchmark 會誤導」

HTTP long polling

HTTP 長輪詢

客戶端發出 HTTP 請求後伺服器先不回應,等有新資料才回;客戶端收到後立刻再發下一個請求。

因為它就是一般的 HTTP 請求,幾乎任何網路環境都能通過,所以相容性最高。但每條「連線」其實是不斷重複的請求,每次都有 header 開銷、每次都可能落到不同伺服器,伺服器還要把「等待中的請求」掛著。效率遠低於 WebSocket,而且擴展它要用 stateless HTTP 的思路,跟 WebSocket 的長連線模型完全不同——作者說「複雜度再加一層」就是指這個。

相關術語: stateless (依循其擴展模型)、WebSocket (對照組)

出處:第 2 段「為什麼 WebSocket benchmark 會誤導」

留給下一段 把通用成本清掉之後,作者說「來看你擴展 WebSocket 的選項」——後端擴展到底有哪幾條路?而其中最直覺的那條(把一台機器加大)能不能直接解決問題?

3. 兩種擴展方式與「一台能撐多少」 3:03–4:14

後端擴展只有兩條路:垂直擴展(scaling up,給同一台機器加 CPU、RAM)與水平擴展(scaling out,加機器並用 load balancer 分流)。作者先看垂直擴展,並提出大家最常問的問題:一台伺服器實際上能撐多少 WebSocket 連線?如果那個數字夠用,就能一直加資源、省掉水平擴展的麻煩。但答案是「沒有答案」,它取決於伺服器資源、WebSocket 實作與你的需求。

垂直 vs 水平擴展的示意圖,一眼看出兩者差在「加大一台」還是「加多台 + load balancer」。
3:25 · 垂直 vs 水平擴展的示意圖,一眼看出兩者差在「加大一台」還是「加多台 + load balancer」。
承上 承上:通用成本(benchmark 失真、fallback)已清掉,現在回答「擴展有哪幾條路」以及「最直覺的那條——把一台加大——夠不夠」。

推理因為上一段把「每條連線到底多貴」講清楚了,所以作者接著把後端擴展的選項攤開:只有兩種——vertical scaling(scaling up,給同一台加 CPU、RAM)和 horizontal scaling(scaling out,加機器,前面放一個 load balancer 平均分流)。他先看垂直擴展,因為它對應到大家(包括他自己)最先問的問題:「一台伺服器實際上能撐多少 WebSocket 連線?」這個問題之所以重要,是因為如果那個數字夠大、能涵蓋你的使用者與成長,就可以一直加資源、避開水平擴展的麻煩。但作者的回答是「沒有好答案」:它取決於伺服器資源、你的 WebSocket 實作,以及你的具體需求——正好呼應第 2 段說的,每條連線的成本取決於你附了哪些「電池」。

AI 補充截圖(205 秒)這一刻畫面只有作者本人,並沒有出現垂直 vs 水平的示意圖,所以這段的理解要靠文字:垂直=一台越換越大,水平=多台一樣的機器加上分流器。作者說「沒有答案」時可以再具體一點:撐多少連線的瓶頸通常不是 CPU 而是記憶體與 OS 限制——每條連線的 socket buffer 加上應用層狀態,從幾 KB 到幾十 KB 不等,一台 16 GB 的機器空連線可以到數十萬,但一加上第 2 段那九項「電池」、再加上訊息真的在流動,數字可能掉一個數量級。所以「一台能撐多少」得用你自己的實作、真實的訊息流量去壓測,別人的數字沒有參考價值。另外作者這裡口誤把「沒有好答案的問題」說成「there isn't a good question to that answer」,意思是「這個問題沒有好答案」。

vertical scaling

垂直擴展(scaling up)

給同一台機器加更多 CPU、記憶體等資源來提高容量。

最簡單的擴展方式:程式碼不用改、架構不用動,換台更大的機器就好。對 WebSocket 這種有狀態的服務特別誘人,因為所有連線狀態都在同一個 process 裡,不需要跨機器同步。但單台機器有物理上限、價格隨規格非線性上升,而且不管多強都只有一台。

相關術語: horizontal scaling (對照組)

出處:第 3 段「兩種擴展方式與「一台能撐多少」」

horizontal scaling

水平擴展(scaling out)

加更多台機器到網路裡,用 load balancer 把負載分散到它們之間。

理論上容量沒有上限,只要一直加機器就好,也天然具備冗餘。但對有狀態的 WebSocket 來說,狀態被切到多台機器上是要付出代價的——作者在這段先按下不表。HTTP 這種 stateless 協定水平擴展幾乎免費,WebSocket 則不是。

相關術語: vertical scaling (對照組)、load balancer (需要)

出處:第 3 段「兩種擴展方式與「一台能撐多少」」

load balancer

負載平衡器

站在一群伺服器前面的軟體或設備,把進來的連線分配到各台伺服器上。

對客戶端來說只看到一個位址;load balancer 收到連線後依某種規則挑一台後端轉過去。對 WebSocket 而言要注意:它在 handshake 時做一次分配,之後這條 TCP 連線就固定黏在那台伺服器上,所以 load balancer 必須支援長連線(不能因為閒置就切斷)。

相關術語: horizontal scaling (核心元件)

出處:第 3 段「兩種擴展方式與「一台能撐多少」」

留給下一段 作者話鋒一轉:「就算那個數字真的很高」,垂直擴展還有一些實務上的考量要知道——他整理了一份小清單,那些問題是什麼?

4. 垂直擴展的實務問題 4:14–6:30

即使那個數字夠高,垂直擴展仍有四個實務問題:一、貴——得按最高峰值配置資源,但多數時間(例如深夜)用不到;二、終究會撞到某個資源限制(thread 數、ephemeral port),要調 kernel 參數,需要專業知識;三、只有一台就是單點故障,升級、重新部署都得挑離峰時間、儘量少做,跟 continuous deployment 背道而馳;四、memory leak 之類的程式錯誤或雲端供應商的區域故障,都會讓整個服務下線。

作者說「我整理了一份小清單」,這張清單畫面是本段四個問題的總覽。
4:17 · 作者說「我整理了一份小清單」,這張清單畫面是本段四個問題的總覽。
承上 承上:作者說「就算數字夠高」垂直擴展仍有實務考量,並整理了一份清單——這段就是逐條過那份清單。

推理因為上一段得出「一台能撐多少」沒有答案、且就算有也不能只看數字,所以作者列出垂直擴展的四個問題。一、貴:得按你預估的最高同時連線數配置資源,但多數時間(例如深夜使用者都離線)根本用不到。二、就算配了很強的機器,也會在某處撞到資源限制——例如 thread 數或 ephemeral port——要靠調 kernel 參數克服,這需要專業知識,作者坦言自己不敢在正式環境做。三、也是核心論點:只要正式環境只有一台 WebSocket 伺服器,不管它多強,就只有一個故障點。升級、重新部署這種例行事務都得小心不讓服務中斷,但單台通常做不到,只能挑離峰、少做,正好是 continuous deployment 的反面。四、更可怕的是災難:程式有 memory leak 之類需要重啟的錯誤,或即使程式完美、雲端供應商的 region / availability zone 暫時離線——不管機器配得多好,都會整個下線。作者由此提出「也許水平擴展能解決其中一些問題」。

AI 補充截圖(257 秒)畫面仍只有作者本人,清單並沒有顯示在畫面上,所以四點要從語音整理。作者沒展開的兩個地方值得補:第一,「按峰值配置」的浪費在垂直擴展下無解,因為單台機器不能半夜縮小、白天變大,而這正是水平擴展可以動態增減機器的動機。第二,「資源限制」對 WebSocket 伺服器來說最先撞到的通常是 file descriptor 上限(每條連線一個 fd,Linux 預設 1024,要調 ulimit 與 fs.file-max)與 conntrack 表,然後才是記憶體。作者提到 ephemeral port 則要看情境:伺服器接受連入時只用一個 listening port,不消耗 ephemeral port;真正會耗盡的是 load balancer 或反向 proxy 對後端建立連線的那一側(每個來源 IP 對每個目標只有約 6 萬個 port 可用)。這段最重要的推理是「單點故障」:它把前面「貴」「撞上限」這些可用錢解決的問題,升級成用錢也解不了的結構問題,這就是為什麼作者接下來要轉向水平擴展。

術語:provisioningkernel parameters

provisioning

資源配置

事先為伺服器準備好足以應付預期負載的 CPU、記憶體等資源。

垂直擴展下你只能為「最壞情況」配置:估一個最高同時連線數,買一台撐得住的機器。問題是負載有日夜與週期起伏,峰值以外的時間資源閒置卻照付錢。這個浪費是結構性的,換更便宜的機器並不能解決,只有能隨負載增減機器的架構才能。

相關術語: vertical scaling (主要成本來源)

出處:第 4 段「垂直擴展的實務問題」

ephemeral port

臨時埠

作業系統為每個對外建立的連線自動分配的來源 port,範圍有限(Linux 預設約 28,000 個)。

TCP 連線由「來源 IP:port + 目標 IP:port」四元組唯一識別。當一台機器對同一個目標建立大量連線時,能用的來源 port 會用完,新連線就建不起來。對 WebSocket 伺服器來說,它接受連入只用一個固定 port,所以自己不會耗盡 ephemeral port;會耗盡的是前面的 load balancer / proxy 對它建連線的那一側。作者把它列為單機限制之一,適用情境要看你的架構。可以用 net.ipv4.ip_local_port_range 調大範圍,或讓 proxy 用多個來源 IP。

相關術語: kernel parameters (以其調整)

出處:第 4 段「垂直擴展的實務問題」

kernel parameters

核心參數

作業系統核心的可調設定(Linux 上透過 sysctl),控制網路、檔案、記憶體等系統層限制。

例如 fs.file-max(全系統 fd 上限)、net.core.somaxconn(accept 佇列長度)、net.ipv4.ip_local_port_range(ephemeral port 範圍)、tcp 相關 buffer 大小。預設值是為一般用途設的,高連線數的 WebSocket 伺服器幾乎一定要調。調錯可能讓整台機器不穩,這就是作者說「需要專業知識、我不敢在正式環境做」的原因。

相關術語: ephemeral port (可調其範圍)

出處:第 4 段「垂直擴展的實務問題」

single point of failure

單點故障

系統中只要某一個元件壞掉,整個服務就跟著停擺的那個元件。

這是本段的核心概念,也是整支影片轉向水平擴展的理由。單台 WebSocket 伺服器不管多強,它掛了所有連線一起斷;而且不只是「壞掉」,連例行的升級、重新部署都等於主動製造一次故障。錢可以買更大的機器,但買不掉「只有一台」這個結構問題。

相關術語: vertical scaling (結構性弱點)、continuous deployment (阻礙)

出處:第 4 段「垂直擴展的實務問題」

continuous deployment

持續部署

程式碼一通過測試就自動、頻繁地部署到正式環境的做法。

它的前提是部署不會中斷服務,通常靠多台機器輪流更新(滾動更新)達成。單台 WebSocket 伺服器每次部署都得重啟、所有連線都會斷,所以只能挑離峰、盡量少部署——作者說這是 continuous deployment 的「antithesis(反面)」。這點常被低估:它不只是穩定性問題,還會拖慢整個團隊的交付節奏。

相關術語: single point of failure (被其阻礙)

出處:第 4 段「垂直擴展的實務問題」

memory leak

記憶體洩漏

程式不斷配置記憶體卻沒有釋放,用量隨時間持續攀升,最終耗盡而崩潰或需重啟。

對長時間執行的 WebSocket 伺服器特別危險,因為 process 幾乎不重啟,小小的洩漏(例如斷線後忘了清掉該連線的訂閱紀錄)累積幾天就能吃光記憶體。作者用它舉例「需要重啟服務的錯誤」:在單機架構下,重啟等於全面停機。

相關術語: single point of failure (觸發其後果)

出處:第 4 段「垂直擴展的實務問題」

availability zone

可用區

雲端供應商在同一地區內彼此獨立的資料中心,設計上一個區故障不影響其他區。

AWS、GCP、Azure 都把一個 region 切成多個 AZ,各自有獨立的電力與網路。單台伺服器必然只在一個 AZ 裡,那個 AZ 出事你就跟著下線——即使你的程式完美無缺。這是作者說「你仍然依賴供應商」的意思,也是水平擴展時應該把機器分散到多個 AZ 的理由。

相關術語: single point of failure (另一種形式)

出處:第 4 段「垂直擴展的實務問題」

見仁見智 4:49
「maybe you hit the limit of available threads or ephemeral」
WebSocket 伺服器接受連入時只用一個 listening port,本身不會耗盡 ephemeral port;會耗盡的是 load balancer / 反向 proxy 對後端建立連線的那一側(每個來源 IP 對同一目標約 6 萬個 port)。單台伺服器最先撞到的通常是 file descriptor 上限(ulimit -n、fs.file-max)與記憶體。是否適用取決於你的架構裡伺服器前面有沒有 proxy,所以標為見仁見智。字幕的「ephemeral pause」是「ephemeral ports」的辨識誤差。
依據: TCP 四元組定義(RFC 793 / RFC 9293);Linux 預設 ip_local_port_range 32768–60999
留給下一段 單機的根本問題是「只有一個故障點」——作者說「也許水平擴展能解決其中一些問題,來仔細看看」:多台機器怎麼分流?分流之後又是誰在指揮?

5. 水平擴展與 load balancer 6:30–7:40

水平擴展把負載分散到多台機器,可以隨需求動態增減伺服器(忙時加、離峰減以省錢),一台掛了其他機器能接手。關鍵元件是 load balancer:它站在機器陣列前面,把進來的 WebSocket 連線平均分配出去。分配演算法有好幾種,預設常見的是 round robin(server 1、server 2、server 1、server 2 輪流)。水平擴展是建立可擴展、穩健後端的方法,但不是加幾台機器、打開 load balancer 就完事。

作者說「畫面上有幾種 load balancing 演算法」,這張圖列出可選演算法名稱,字幕沒有念出來。
7:16 · 作者說「畫面上有幾種 load balancing 演算法」,這張圖列出可選演算法名稱,字幕沒有念出來。
承上 承上:單機的根本問題是單點故障,作者轉向水平擴展,看多台機器怎麼分流、由誰指揮——這段回答的就是「動態增減」與「load balancer 怎麼分」。

推理因為上一段垂直擴展的四個問題裡,「貴」來自無法隨負載調整、「單點故障」來自只有一台,所以作者接著說明水平擴展正好各個擊破:把負載分散到多台機器後,可以隨需求動態加減伺服器——忙時加、深夜減省錢;一台因任何原因下線也不是世界末日,陣列裡另一台大概能接手。要做到這些,關鍵是 load balancer:從後端架構看它站在機器陣列前面,把進來的 WebSocket 連線平均分配。分配演算法有幾種,畫面上有列,但很多情況預設是 round robin:server 1、server 2、server 1、server 2 輪流。作者總結水平擴展是建立真正可擴展、穩健後端的方法——但馬上補一句:它不是加幾台機器、打開 load balancer 就完事。

AI 補充截圖(436 秒)作者說「這裡畫面上有幾種演算法」,但抽到的這格只有作者本人,沒抓到那張清單,所以補上常見的幾種:round robin(輪流)、least connections(挑目前連線最少的)、IP hash(同一來源 IP 固定到同一台)、weighted 版本(依機器規格給權重)。對 WebSocket 有一個作者沒說、但下一步推理需要的重點:load balancer 只在 handshake 那一刻做分配,之後這條長連線就固定在那台伺服器上,不會再被重新分配。所以 round robin 分的是「新連線」,而不是「訊息」——這表示某個使用者這輩子的所有訊息都只經過他被分到的那一台。另外 round robin 對 WebSocket 不一定平均:連線是長命的,先分到的伺服器上舊連線不會走,加上第 2 段說的每條連線活躍度不同,實際負載可能很不均,least connections 通常更適合長連線。

術語:autoscalingload balancing algorithm

autoscaling

自動擴縮

依據實際負載自動增加或移除伺服器數量。

作者說的「dynamically add or remove servers in response to changes in demand」就是這件事。它直接解決第 4 段「按峰值配置、離峰浪費」的問題:白天開十台、半夜留兩台,費用跟著用量走。對 WebSocket 要注意縮減時不能直接砍機器,因為上面還掛著長連線,得先讓連線優雅地搬走,這是水平擴展要另外處理的難題。

相關術語: horizontal scaling (帶來的能力)、provisioning (取代靜態版)

出處:第 5 段「水平擴展與 load balancer」

load balancing algorithm

負載平衡演算法

load balancer 決定「這條新連線該給哪台伺服器」的規則。

常見有 round robin、least connections、IP hash、以及各自的加權版本。對短命的 HTTP 請求,round robin 就很平均;對長命的 WebSocket 連線,因為分配後不會再移動,累積下來的負載可能失衡,通常會偏好 least connections 或依伺服器實際負載回報來分。演算法選擇也影響縮減機器時的行為。

相關術語: load balancer (設定項)、round robin (一種)

出處:第 5 段「水平擴展與 load balancer」

round robin

輪流分配

把連線依序輪流分給每台伺服器:1、2、3、1、2、3……

最簡單、也是許多 load balancer 的預設。它不看伺服器目前忙不忙,只管輪流,所以在每條連線成本差不多、壽命短的情況下最有效。作者用「server one, server two, server one, server two」示範。對 WebSocket 而言它保證的只是「新連線數」平均,不保證各台的實際負載平均。

相關術語: load balancing algorithm (預設實作)

出處:第 5 段「水平擴展與 load balancer」

留給下一段 作者說「不幸的是,沒那麼簡單」、「水平擴展最大的缺點是它引入的架構複雜度」——具體是什麼複雜度?他準備了一張圖來說明。

6. 狀態分裂與 backplane 7:40–9:55

水平擴展最大的代價是架構複雜度。作者用示意圖說明:load balancer 把連線分到不同伺服器,但連在 server 1 的客戶端收不到送到 server 2 的訊息。以聊天室為例,user A 在 server 1、user B 在 server 2,兩台之間沒有連結,server 2 完全不知道 server 1 發生什麼,A 的訊息永遠到不了 B;廣播也一樣,連線清單被切碎在兩台上,沒有單一地方可以拿到全部連線。解法是把連線狀態放到 process 之外,用 message broker(常見是 Redis 搭 pub/sub),server 1 透過 Redis 把訊息轉給 server 2 再送給 user B。這叫加一層 backplane,讓所有伺服器共享同步的狀態視圖。

作者明說「我有一張小圖來說明」:load balancer 把連線分到 server 1 / server 2 的架構圖。
7:50 · 作者明說「我有一張小圖來說明」:load balancer 把連線分到 server 1 / server 2 的架構圖。
同一張圖強調 server 1 與 server 2 之間「沒有連線」,是狀態分裂問題的視覺證據。
8:28 · 同一張圖強調 server 1 與 server 2 之間「沒有連線」,是狀態分裂問題的視覺證據。
加上 Redis 後的 backplane 架構圖:server 1 → Redis → server 2 → user B,是本段的解答畫面。
9:32 · 加上 Redis 後的 backplane 架構圖:server 1 → Redis → server 2 → user B,是本段的解答畫面。
承上 承上:作者說水平擴展最大的缺點是架構複雜度,並準備了一張圖——這段就是用那張圖把「複雜度」具體化:連線被分到不同伺服器之後,狀態怎麼辦?

推理因為上一段 load balancer 把連線平均分到不同伺服器(這是分散負載的好方法),所以作者接著指出代價:連在 server 1 的客戶端收不到送往 server 2 的訊息。他用聊天室舉例:load balancer 把 user A 分到 server 1,round robin 輪到 user B 分到 server 2。A 透過 server 1 送訊息給 B,但 B 在 server 2,圖上兩台之間沒有任何連線,server 2 完全不知道 server 1 上發生了什麼——它們成功分散了負載,但從狀態的角度是完全斷開的,A 的訊息根本沒有機會送到 B。第二個例子是廣播:要對所有連線推一則即時更新,最方便的寫法是拿到全部 WebSocket 連線的清單、迴圈逐一送出;但現在連線碎在兩台上,沒有任何一個地方能拿到完整清單。解法是把連線狀態放到 process 之外,交給 message broker——很多開發者選 Redis 搭 pub/sub 模式。回到聊天室:A 透過 server 1 送訊息,server 1 經由 Redis 轉給 server 2,等於在兩台之間建了一條連結,server 2 再透過 B 的 WebSocket 連線送給 B。這有時叫做替基礎設施加一層 backplane,讓各台伺服器對狀態有共享且同步的視圖。

AI 補充三張截圖是同一張圖的三個階段。470 秒:User A(橘線)與 User B(紫線)各自連到 Load balancer,橘線被轉到 Server 1、紫線被轉到 Server 2——顏色清楚表示兩條連線走的是完全不同的路。508 秒:同一張圖,作者這時正說「there's no link between server 1 and server 2」,畫面上 Server 1 與 Server 2 之間確實什麼都沒有。572 秒:右側多了一個 Redis,Server 1 與 Server 2 各有一條雙向的淺藍色線連到它——這條線就是新增的「link」,訊息路徑變成 A → LB → Server 1 → Redis → Server 2 → B。作者跳過了一步:為什麼放到「process 外」就解決了?因為第 1 段講的 stateful 資源(socket 本身)仍然只能留在握有那條 TCP 連線的伺服器上,搬不走;能搬走的是「誰在哪、誰訂閱了什麼、有什麼訊息要送」這層應用狀態。把這層集中到 Redis 之後,任一台伺服器發布訊息,所有訂閱的伺服器都收到,再各自檢查自己手上有沒有目標 client 的 socket。所以 backplane 不是把連線集中,而是把「訊息與狀態的可見性」集中,socket 仍然分散。也要注意 Redis pub/sub 是 fire-and-forget:訂閱者當時不在線就收不到,這跟第 2 段說的 buffering 需求有衝突,需要另外處理(例如 Redis Streams 或有持久化的 broker)。

message broker

訊息代理

位於各服務之間、負責接收與轉發訊息的中介元件,讓發送方與接收方不必直接互相認識。

在這裡它扮演的是「所有 WebSocket 伺服器共同看得到的地方」:server 1 不用知道 B 在哪一台,只要把訊息交給 broker,持有 B 連線的那台自然會收到。常見選擇有 Redis、RabbitMQ、Kafka、NATS,各自在持久化、順序保證、吞吐上取捨不同。作者選 Redis 舉例是因為它最常見、pub/sub 模式最直觀。

相關術語: Redis (一種)、backplane (實作於)

出處:第 6 段「狀態分裂與 backplane」

Redis

Redis(記憶體資料庫)

以記憶體為主的高速鍵值資料庫,內建 pub/sub 功能,常被拿來當服務間的共享狀態與訊息通道。

延遲在毫秒以下、部署簡單,所以成為 WebSocket backplane 最常見的選擇。除了 pub/sub 也能用來存「哪個 user 連在哪台」這類對照表。要注意純 pub/sub 不保存訊息、單一 Redis 節點也可能成為瓶頸或故障點;正式環境通常會用 Redis Cluster 或 Sentinel 做複製。

相關術語: message broker (常見實作)、pub/sub (提供)

出處:第 6 段「狀態分裂與 backplane」

pub/sub

發布/訂閱

發送方把訊息發布到某個頻道,所有訂閱該頻道的接收方都會收到,雙方互不直接連線。

每台 WebSocket 伺服器啟動時訂閱相關頻道(例如某個聊天室),任何一台收到 client 訊息就發布到該頻道,其他台就會收到並轉給自己手上的 client。它讓「伺服器數量」與「訊息路由」解耦:加第三台伺服器只要它也訂閱就好。代價是廣播式的 fan-out:每則訊息會送到所有訂閱的伺服器,即使那台上沒有相關 client。

相關術語: broadcast (實現方式)、Redis (由其提供)

出處:第 6 段「狀態分裂與 backplane」

backplane

背板/後端匯流

在多台伺服器背後加的一層共享通道,讓它們能交換訊息、對狀態有一致的視圖。

這個詞借自硬體:機箱裡把各插卡連在一起的那塊板子。在 WebSocket 架構裡指的就是 message broker 這一層。重點是它集中的是「訊息與應用狀態的可見性」,不是 socket 本身——每條 TCP 連線仍然只在一台伺服器上,backplane 只負責讓正確的那台知道該送什麼。SignalR、Socket.IO 的 Redis adapter 都是這個模式的實作。

相關術語: message broker (由其實作)、horizontal scaling (必要補丁)

出處:第 6 段「狀態分裂與 backplane」

broadcast

廣播

把同一則訊息送給所有(或某個群組內全部)已連線的客戶端。

單機時很簡單:拿全部連線的清單迴圈送出。多機後沒有任何一台握有完整清單,所以要改成「發布到頻道、每台各自對自己的連線迴圈」。作者用它當第二個例子,是為了說明狀態分裂不只影響一對一訊息,任何需要「全域視野」的操作都會壞掉。

相關術語: pub/sub (多機下的實作)

出處:第 6 段「狀態分裂與 backplane」

留給下一段 作者反問:「所以水平擴展是魔法銀彈嗎?完全不是」——加了 backplane 之後,水平擴展自己又帶來哪些挑戰?

7. 水平擴展的挑戰 9:55–11:38

水平擴展不是銀彈。主要挑戰是資料同步:除了訊息,還要同步連線狀態(user A 離線時通知 user B)。而且狀態集中在 Redis 後,Redis 變成新的單點故障,得考慮如何複製 broker。另一個負擔是單台伺服器逼近硬體上限時怎麼辦:要偵測快滿了、先拒絕新連線、再主動踢掉部分既有連線(load shedding),讓它們重連到較健康的節點。這又引出恢復連線的問題:不管是被踢還是伺服器掛掉,大量連線會同時湧向同一台伺服器(thundering herd),造成連線錯誤、延遲升高,甚至把那台也拖垮。

承上 承上:作者自問「水平擴展是銀彈嗎?完全不是」——這段就是列出加了 backplane 之後,水平擴展自己帶來的挑戰。

推理因為上一段用 Redis backplane 解決了訊息送不到的問題,所以作者接著指出這個解法本身的代價。第一,主要挑戰是資料同步:除了剛講的訊息,還得同步連線狀態——user A 離線時要通知 user B(聊天室顯示對方離線)。第二,既然應用狀態都放進 Redis 了,Redis 就是一個新的單點故障,所以要考慮怎麼複製 Redis 或你用的任何 broker,讓系統在故障時仍然穩健。第三,後端開發者的另一個負擔是「陣列裡某台伺服器逼近硬體上限時該怎麼辦」:要有機制偵測快到上限、先拒絕新連線(不要讓情況更糟),然後大概還得踢掉一部分既有連線(強制斷線),它們會嘗試重連,希望能落到比較健康的節點——作者坦言這個機制實作起來很棘手。第四,它又引出另一個麻煩:恢復連線。不管是你主動把連線從一台踢到另一台,還是某台就是掛了,兩種情況都會有一大批連線同時湧向同一台伺服器,給它不當的壓力,導致連線錯誤、連線延遲、效能下降、延遲上升,甚至那台也跟著下線。作者收尾說這些問題都能解,但都需要一定程度的複雜度。

AI 補充這段沒有截圖。作者列的四點其實是一條因果鏈,補上中間的邏輯會更清楚:(1) 訊息要同步 → 用 backplane;(2) 但 backplane 集中了狀態 → 它變成第 4 段說的 single point of failure,於是繞了一圈又回到「單點」問題,只是從伺服器搬到了 Redis;(3) 多台機器各自有上限 → 要能在單台快滿時把負載往外推,這就是 load shedding;(4) 但被推出去的連線會同時重連 → thundering herd。作者說「這些問題都能解」但沒說怎麼解,補幾個標準做法:連線狀態同步通常用 presence 機制(每台伺服器把「我手上有誰」寫進 Redis 並帶 TTL,斷線或機器掛掉時自動過期);Redis 單點用 Sentinel 或 Cluster 做主從複製與自動 failover;thundering herd 的標準解是客戶端重連時用 exponential backoff 加 jitter,把重連時間打散,而不是全部在同一秒衝回來;伺服器端也可以在 load balancer 上做連線速率限制。這裡也解釋了第 5 段預告的問題:autoscaling 縮減機器時不能直接砍,就是因為會製造一次人為的 thundering herd。

presence

在線狀態

追蹤每個使用者目前是否在線、連在哪裡,並在變動時通知關心的人。

作者說的「sync connection states so if user A goes offline user B can be notified」就是 presence。多機下的困難在於 user A 的 socket 只有一台伺服器知道,它斷線時那台要主動把「A 離線」發布出去;如果那台整個掛掉,它來不及發布,所以常用的做法是每台定期在 Redis 更新帶 TTL 的紀錄,機器消失後紀錄自動過期。

相關術語: backplane (透過其同步)

出處:第 7 段「水平擴展的挑戰」

replication

複製

把同一份資料同步維持在多個節點上,主節點故障時由副本接手。

作者說要「replicate Redis or whatever broker you're using」。Redis 的做法是主從複製加 Sentinel(監控與自動切換)或 Redis Cluster(分片加複製)。這樣 backplane 才不會變成新的單點故障——否則你只是把單點從 WebSocket 伺服器搬到了 Redis。

相關術語: single point of failure (消除手段)、Redis (施加於)

出處:第 7 段「水平擴展的挑戰」

load shedding

卸載

伺服器接近上限時主動拒絕新請求、甚至斷開部分既有連線,以保護自己不被壓垮。

作者描述的三步驟:偵測快到上限 → 拒絕新連線 → 踢掉部分既有連線讓它們重連到健康節點。難點在於「踢誰」「踢多少」「怎麼確保它們不會又回到同一台」;踢太多會製造 thundering herd,踢太少救不了自己。通常會搭配 load balancer 的健康檢查,讓快滿的機器暫時不接新連線。

相關術語: thundering herd (可能引發)、autoscaling (縮減時需要)

出處:第 7 段「水平擴展的挑戰」

thundering herd

驚群效應

大量客戶端在同一時刻一起重連或請求,瞬間壓垮目標伺服器。

作者說「a bunch of connections can come thundering home hitting the same server at the same time」。觸發原因有兩種:你主動 shed 連線,或某台伺服器掛掉。結果是連線錯誤、延遲升高,甚至再掛一台,形成連鎖。標準解法在客戶端:重連前等待 exponential backoff 的時間並加上隨機 jitter,把重連分散開來;伺服器端則限制每秒接受的新連線數。

相關術語: load shedding (副作用)、exponential backoff (解法)

出處:第 7 段「水平擴展的挑戰」

exponential backoff

指數退避

每次重試失敗後,把等待時間加倍(1s、2s、4s、8s…),並通常加上隨機 jitter 打散。

如果所有客戶端都固定每 1 秒重連一次,伺服器就會每秒被同一群人打一次;指數退避讓失敗越多的客戶端等越久,jitter(隨機抖動)則讓同時斷線的客戶端不會在同一毫秒重連。這是解 thundering herd 最便宜也最有效的手段,但它是第 2 段清單裡「Automatic reconnection」的一部分,原生 WebSocket 不會替你做。

相關術語: thundering herd (解法)、heartbeat (搭配偵測斷線)

出處:第 7 段「水平擴展的挑戰」

留給下一段 所有問題都能解、但都要付出複雜度——那到底該不該走水平擴展?作者回到影片一開始那個問題「一台能撐多少連線」,準備給出他的最終看法。

8. 結論:依需求選擇 11:38–14:00

回到「一台能撐多少連線」:這個問題本身就問錯了,因為沒有兩條連線是一樣的(活躍程度不同),而且單機就是單點故障,會影響使用者信心甚至業務連續性。水平擴展是建立可靠、高擴展性 WebSocket 後端的關鍵,但要管理 load balancer、多台伺服器和狀態同步。作者不下定論:有些公司確實用一台垂直擴展、程式碼優化良好且容錯的伺服器,接受停機風險以換取簡單;但金融等即時體驗是核心流程、不能接受停機的服務,就值得一開始投資水平擴展。

承上 承上:所有問題都能解但都要付複雜度,作者回到開場的問題「一台能撐多少連線」,給出他的最終看法。

推理因為前面已經走完垂直擴展的四個問題與水平擴展的四個挑戰,所以作者能對開場的問題下判斷:「一台伺服器能撐多少 WebSocket 連線」根本是個問錯的問題(作者說 mute question,應為 moot question)。理由一,沒有兩條連線是一樣的,有的比別的活躍得多,所以「連線數」本身不是好的容量單位;理由二,只有一台就有單點故障,會讓應用容易停機,影響使用者對服務的信心,甚至影響業務連續性。影片的主結論是:水平擴展是建立可靠、高擴展性 WebSocket 後端的關鍵,但它引入複雜度——你得管理 load balancer、引入多台伺服器,還得想辦法在後端伺服器之間同步狀態。那水平擴展是不是「預設答案」?作者的回答是「也許,只有你知道你在做什麼」:他從研究與跟工程師的對談中得知,確實有些公司就用一台垂直擴展的伺服器,只要程式碼優化得好、有容錯,能撐相當多連線;風險是停機,而在你應用的這個階段,這個風險可能比承擔水平擴展的所有複雜度划算。反過來,金融應用這類即時體驗就是核心流程、完全不能停機的服務,一開始就投資水平擴展是合理的。作者說他不是來告訴你哪個對,只是把選項與挑戰攤開。

AI 補充這段沒有截圖。作者用「連線各不相同」和「單點故障」兩個理由否定「一台能撐多少」這個問題,其實對應影片的兩條線:前者是第 2、3 段講的「每條連線成本取決於實作與活躍度,所以沒有通用數字」;後者是第 4 段的結構性問題。他最後的取捨框架可以整理成一句:用「停機的代價」去換「架構複雜度」——停機代價低(內部工具、早期產品、非核心功能)就先用單台加好的容錯程式碼,停機代價高(金融、交易、即時協作)就一開始做水平擴展。作者沒提但常見的中間路線:先用單台、但一開始就把應用狀態放在 process 外(例如 Redis)而不是記憶體裡,這樣日後加第二台時只需要加 load balancer,不必重寫狀態邏輯;以及乾脆把這整層外包給託管的即時訊息服務——這也是作者所屬公司 Ably 的產品,觀看時可留意這層立場。

fault tolerance

容錯

系統在部分元件出錯時仍能繼續正確運作(或優雅降級)的能力。

作者說單台伺服器若跑的是「well optimized and fault tolerant websocket code」也能撐不少連線。在單機情境下,容錯指的是程式層面:例外不會讓 process 崩潰、單一連線的錯誤不影響其他連線、資源用完時有保護機制。這能降低但無法消除單點故障——機器或 AZ 掛掉時再好的程式也救不了。

相關術語: single point of failure (緩解但不消除)、vertical scaling (單機的必要條件)

出處:第 8 段「結論:依需求選擇」

business continuity

業務連續性

組織在故障或災難發生時,維持關鍵業務不中斷、或在可接受時間內恢復的能力。

作者用它來說明停機的代價不只是技術問題:對金融、交易平台這類服務,即時功能本身就是業務,停幾分鐘可能就是實際損失或違反法規。這是作者判斷「值不值得一開始投資水平擴展」的關鍵尺度——停機代價越接近業務核心,越該提早付複雜度。

相關術語: horizontal scaling (投資理由)

出處:第 8 段「結論:依需求選擇」

留給下一段 總結收束

4. 總結

WebSocket 是有狀態的長連線,伺服器要為每條連線常駐 memory 與 CPU(第 1 段)→ 所以 benchmark 的「百萬連線」不可信,上線還要 heartbeat、buffering、long polling fallback(第 2 段)→ 擴展只有垂直與水平兩條路,而「一台能撐多少」沒有答案(第 3 段)→ 就算數字夠大,垂直擴展仍貴、會撞資源限制、是單點故障、無法無中斷部署(第 4 段)→ 水平擴展用 load balancer 分流、可動態增減、一台掛了別台接手(第 5 段)→ 但連線分散後狀態就碎了:A 在 server 1 的訊息到不了 server 2 的 B,廣播也拿不到完整清單,解法是把狀態放到 process 外、用 Redis pub/sub 當 backplane(第 6 段)→ backplane 又帶來同步、Redis 單點、load shedding、thundering herd 等挑戰(第 7 段)→ 結論:「一台能撐多少」是問錯的問題,水平擴展是可靠後端的關鍵但複雜度自己扛;能接受停機就一台也行,不能停機的服務值得一開始就投資水平擴展(第 8 段)。

勘誤總整理

確定錯誤/已過時見仁見智(取決於版本或情境)

段落原話(transcript 逐字)說明
4. 垂直擴展的實務問題
4:49
「maybe you hit the limit of available threads or ephemeral」WebSocket 伺服器接受連入時只用一個 listening port,本身不會耗盡 ephemeral port;會耗盡的是 load balancer / 反向 proxy 對後端建立連線的那一側(每個來源 IP 對同一目標約 6 萬個 port)。單台伺服器最先撞到的通常是 file descriptor 上限(ulimit -n、fs.file-max)與記憶體。是否適用取決於你的架構裡伺服器前面有沒有 proxy,所以標為見仁見智。字幕的「ephemeral pause」是「ephemeral ports」的辨識誤差。
依據: TCP 四元組定義(RFC 793 / RFC 9293);Linux 預設 ip_local_port_range 32768–60999

5. 推薦三個下一步

1. 往下挖深:Redis pub/sub backplane 實作

第 6 段只用一張圖說「server 1 經由 Redis 轉給 server 2」,沒有講訂閱哪個 channel、訊息格式、以及 Redis 掛了怎麼辦(第 7 段的 broker 單點)。實際動手接一次才知道 backplane 的邊界在哪。

YouTube 搜尋:Redis pub/sub WebSocket multiple servers socket.io redis adapter explained scaling websockets redis backplane

2. 往旁邊對照:Server-Sent Events 與 HTTP long polling 的擴展方式

第 2 段說 fallback transport 的擴展方式「跟 WebSocket 完全不同」,但沒有展開。對照 SSE / long polling 在 load balancer 與狀態上的差異,才能判斷自己的場景是否非用 WebSocket 不可。

YouTube 搜尋:WebSocket vs Server-Sent Events scaling HTTP long polling vs WebSocket SSE load balancer sticky sessions

3. 往上應用:load shedding、backoff 與連線恢復的系統設計

第 7 段點出 load shedding 與 thundering herd「很棘手」但沒說怎麼做。這正是把影片內容用在真實系統時最先撞到的問題:客戶端重連策略(exponential backoff、jitter)與伺服器端的過載保護要一起設計。

YouTube 搜尋:thundering herd problem websocket reconnect exponential backoff with jitter load shedding system design

📄 全部影片 · 主題區: 網路與 API 基礎