websocket在秒殺場景下連接過多的問題
這可能是很多人第一次在高并發場景(尤其是秒殺活動)引入 WebSocket 時最容易忽略的隱患點之一。
有兩點非常關鍵:
1?? 高并發場景下 WebSocket 連接數過多;
2?? WebSocket 是否占用 Spring Boot / Tomcat 的 Web 層資源,會不會影響吞吐量。
我們下面一步步拆解,先講本質,再給出在高并發秒殺系統中的優化與架構實踐方案。
一、WebSocket 的連接本質與資源消耗
WebSocket 建立連接后,本質上是一個 TCP 長連接,
底層對應操作系統的 Socket 連接 + 一些用戶態對象(Session、Buffer 等)。
對于每個連接,服務器端主要會占用三類資源:
| 資源類型 | 說明 | 典型占用 |
|---|---|---|
| TCP Socket | 內核 fd 描述符 + TCP buffer | 每連接約 1~2KB |
| 應用對象 | WebSocketSession + 用戶上下文 | 每連接約 2~5KB |
| 線程 / EventLoop | 如果用阻塞 IO,線程可能被阻塞 | 依框架模型不同 |
舉個例子:
10 萬連接 × 3KB = 300MB;
1 百萬連接 × 3KB = 3GB;
資源上不是“不能接受”,關鍵在于并發 IO 線程模型。
二、Tomcat 與 WebSocket 的線程模型(重點)
Spring Boot 默認內嵌的 WebSocket 實現使用的是 Tomcat (BIO/NIO),
其線程模型大致如下:
-
HTTP 請求 → 占用 Tomcat 的 Request-Worker 線程,處理完釋放;
-
WebSocket 連接 → 一旦升級成功,不再復用原 HTTP 線程;
-
Tomcat 會用內部的 NIO Selector 來管理連接;
-
每個連接不會占用獨立線程;
-
但仍然消耗一定的內核資源與 JVM 內存。
-
?? 所以結論是:
WebSocket 連接建立后不會長期占用 Tomcat 的 HTTP worker 線程,
但仍占用內核 fd、NIO selector、內存等資源。
不過 Tomcat 并不擅長管理海量長連接(比如 10 萬+),
它是傳統 Web 應用容器,不是高并發推送服務器。
在秒殺這種極端峰值場景下,就容易成為瓶頸。
三、在秒殺系統中如何應對高并發 WebSocket 連接
? 方案一:Tomcat 小規模(≤5000連接)場景可直接使用
適用場景:
-
只是活動瞬間的短時連接;
-
用戶量可控(幾千并發);
-
僅用于實時推送結果(1~2 秒后斷開)。
優化建議:
# application.properties 調優參數示例 server.tomcat.max-connections=10000 server.tomcat.accept-count=2000 server.tomcat.threads.max=500 server.tomcat.connection-timeout=20000
這種場景下 WebSocket 可以直接跑在 Spring Boot + Tomcat 上,
例如中小型活動(每次幾千人參與)是完全足夠的。
? 方案二:分離 WebSocket 服務(推薦)
當活動用戶量達到數萬到百萬級,應采用連接與業務分離:
架構思路:
┌─────────────┐
│ 前端 (瀏覽器) │
└──────┬────────┘
│
▼
┌──────────────┐
│ WebSocket 網關 │ ← 專門維護長連接
│ (Netty / Spring WebFlux) │
└────────┬────────┘
│
消息通知通道 (Redis Pub/Sub / MQ)
│
┌────────▼────────┐
│ 業務服務 (Spring Boot) │
└──────────────────┘
? 實現重點:
| 模塊 | 作用 | 說明 |
|---|---|---|
| WebSocket 網關 | 管理百萬長連接 | 用 Netty / Gateway NIO 模型 |
| 消息總線 | 轉發業務事件 | Redis Pub/Sub / Kafka |
| 業務服務 | 處理下單邏輯 | 僅做異步下單、狀態變化推送 |
?? 業務服務落單成功 → 通過 Redis 發布 "user_123:success" →
WebSocket 網關訂閱到后,推送消息到對應連接。
這樣:
-
WebSocket 長連接和 HTTP 短請求完全分離;
-
業務服務不再維護連接狀態;
-
可水平擴展(連接節點 + 業務節點獨立伸縮)。
? 方案三:短連接優化(Hybrid 模式)
對于“秒殺活動這種瞬時高峰”,可以采用 短連接 + WebSocket 快速推送:
-
用戶點擊下單 → 建立 WebSocket;
-
等到推送結果(1~2 秒);
-
收到后自動關閉連接。
這樣同時滿足:
-
實時性;
-
不會長期占用連接資源;
-
用戶行為天然觸發清理。
四、實際項目中的選型建議
| 并發量級 | 推薦方案 | 技術棧 |
|---|---|---|
| ≤ 1 萬 | Tomcat + Spring WebSocket | 簡單穩定 |
| 1 萬 ~ 10 萬 | 獨立 WebSocket 服務(Spring WebFlux / Netty) | 分離連接管理 |
| ≥ 10 萬 | IM 級推送平臺(Netty + Redis + Kafka) | 大規模長連接 |
| 秒殺活動短時爆發 | Hybrid 模式(短連+推送后斷開) | 性價比高 |
五、總結回答兩個問題:
Q1:在秒殺高并發下,WebSocket 連接不會太多導致問題嗎?
? 會有問題,如果直接用 Spring Boot + Tomcat 承載數萬連接,會:
-
消耗大量內存;
-
消耗內核 fd;
-
Selector 負載高;
-
GC 壓力上升。
? 解決方式:
-
采用獨立 WebSocket 服務;
-
或者僅短時保活(Hybrid 模式);
-
或者通過 Redis Pub/Sub 消息網關分流。
Q2:WebSocket 是否占用 Spring Boot / Tomcat 的 Web 層連接,會影響吞吐嗎?
? WebSocket 連接建立后不會占用 Tomcat 的 worker 線程,
但仍消耗 IO selector 與內存資源。
在連接數很大時,會間接拖慢 HTTP 請求處理。
? 最佳實踐:
-
業務 HTTP 請求與 WebSocket 服務拆分;
-
或者使用基于 Reactor Netty / Undertow 的異步容器。
六、一個成熟的“秒殺系統推送層”架構建議(可直接落地)
【推薦架構】
┌────────────────────────────┐
│ Nginx / Gateway │
│ 路由 / 負載均衡層 │
└──────────────┬──────────────┘
│
┌───────┴────────┐
│ │
┌───────────────┐ ┌───────────────┐
│ WebSocket節點A │ │ WebSocket節點B │ ← 使用 Netty
│ 維護長連接池 │ │ 負責推送消息 │
└───────────────┘ └───────────────┘
│ │
└──────┬──────────┘
▼
Redis Pub/Sub or Kafka
│
▼
業務服務節點(Spring Boot)
- 下單邏輯
- 消息推送通知
這樣一來:
-
業務節點不用維護連接;
-
推送層可水平擴展;
-
并發百萬也穩定運行。

浙公網安備 33010602011771號