这可能是很多人第一次在高并发场景(尤其是秒杀活动)引入 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)- 下单逻辑- 消息推送通知
这样一来:
-
业务节点不用维护连接;
-
推送层可水平扩展;
-
并发百万也稳定运行。