SSE、长轮询与 WebSocket 连接资源对比及 Spring Boot 配置指南

一、背景

在构建实时消息推送系统时,开发者常面临三种主流技术选型:

  • 长轮询(Long Polling)
  • SSE(Server-Sent Events)
  • WebSocket

三者在连接模型、资源消耗、扩展性等方面差异显著。本文旨在对比其连接资源占用特性,并提供 Spring Boot 项目中的最佳实践与配置建议


二、连接模型与资源消耗对比

特性 长轮询 SSE WebSocket
通信方向 客户端拉(伪推) 服务器 → 客户端(单向) 双向
连接类型 短连接(但 hold 住) 持久 HTTP 连接 TCP 升级后独立连接
是否长期占用 HTTP 连接 ✅ 是(每次请求 hold 30~60s) ✅ 是(连接持续打开) ❌ 否(脱离 HTTP 协议栈)
线程模型 每请求占 1 线程(阻塞) 异步非阻塞(不占处理线程) 异步非阻塞(NIO)
并发连接压力 ⚠️ 极高(易线程爆炸) ⚠️ 高(受 socket 数限制) ✅ 低(单线程可处理数千连接)
适用场景 兼容老旧系统(最后选择) 通知、日志、行情等单向推送 聊天、游戏、协作编辑等双向交互

核心结论

  • 长轮询资源消耗最大,应避免用于高并发场景
  • SSE 比长轮询高效,适合中等规模单向推送
  • WebSocket 是高并发、低延迟、双向通信的首选

三、Spring Boot 中的连接数配置

3.1 Web 容器选择建议

容器 适用场景 优势
Tomcat 默认,通用场景 稳定、生态完善
Undertow 推荐用于 SSE / 长轮询 内存占用低,支持高并发连接
Netty(WebFlux) 超高并发或 Reactive 架构 完全非阻塞,单机支持 10w+ 连接

🔧 切换为 Undertow(Maven)

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

3.2 Tomcat 配置(application.yml)

yaml 复制代码
server:
  tomcat:
    max-connections: 20000      # 最大 socket 连接数(默认 8192)
    accept-count: 200           # 请求等待队列大小
    threads:
      max: 500                  # 处理线程数(SSE 建立后不占此线程)
      min-spare: 50
    connection-timeout: 60000   # 连接超时(毫秒)

⚠️ 注意 :SSE 连接建立后不占用 threads.max,但受 max-connections 限制。


3.3 Undertow 配置(推荐)

yaml 复制代码
server:
  undertow:
    io-threads: 8               # IO 线程数 ≈ CPU 核数
    worker-threads: 200         # 阻塞任务线程
    buffer-size: 1024
    queues:
      task: 1024                # 任务队列大小

✅ Undertow 默认支持数万并发连接,内存效率优于 Tomcat。


3.4 系统级限制(Linux)

每个 TCP 连接 ≈ 1 个文件描述符(fd),需调整系统限制:

bash 复制代码
# 查看当前限制
ulimit -n

# 临时提升(需 root)
ulimit -n 65536

# 永久生效:编辑 /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536

💡 建议:ulimit -n ≥ 预期最大连接数 × 1.2


四、容量估算与选型建议

用户规模 推荐方案 关键配置
< 1,000 SSE + Tomcat 默认配置即可
1,000 ~ 50,000 SSE + Undertow + Redis Pub/Sub max-connections=50000 + ulimit -n 65536
> 50,000 或需双向通信 WebSocket + NettyWebFlux Reactive SSE 集群部署 + 连接分片

五、SSE 项目优化 Checklist

  • 使用 Undertow 替代 Tomcat(降低内存)
  • 配置 server.undertow.max-connections 足够大
  • 系统 ulimit -n 调高(> 连接数 × 1.2)
  • 使用 Spring 的 SseEmitter(已支持异步)
  • 及时清理失效连接 (注册 onTimeout / onError 回调)
  • 集群环境使用 Redis Pub/Sub 广播消息
  • 通过 /actuator/metrics 监控在线连接数

六、附:Reactive SSE(WebFlux)示例(超高并发)

java 复制代码
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> events() {
    return Flux.interval(Duration.ofSeconds(1))
               .map(seq -> ServerSentEvent.builder("tick-" + seq).build());
}

✅ 基于 Reactor 模型,单机可支持 10万+ 并发连接,适合大型实时系统。


七、总结

问题 回答
SSE 会占用很多 HTTP 连接吗? ✅ 会,每个用户占 1 个持久 HTTP 连接,但比长轮询高效得多
WebSocket 会占用很多连接吗? ❌ 不会,基于 NIO,连接成本极低
Spring Boot 需要配置连接数吗? 必须配置! 尤其是 max-connections 和系统 ulimit

🎯 选型口诀
单向推送用 SSE,双向交互选 WebSocket,长轮询仅作兜底。


📌 文档结束

如需完整可运行的 Spring Boot + SSE + Redis 集群示例工程,请联系作者获取。


相关推荐
猫头虎2 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
MZ_ZXD0014 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
invicinble4 小时前
springboot的核心实现机制原理
java·spring boot·后端
space62123275 小时前
在SpringBoot项目中集成MongoDB
spring boot·后端·mongodb
默默前行的虫虫5 小时前
解决EMQX WebSocket连接不稳定及优化WS配置提升稳定性?
websocket
那就回到过去6 小时前
MPLS多协议标签交换
网络·网络协议·hcip·mpls·ensp
金牌归来发现妻女流落街头6 小时前
【从SpringBoot到SpringCloud】
java·spring boot·spring cloud
皮卡丘不断更6 小时前
手搓本地 RAG:我用 Python 和 Spring Boot 给 AI 装上了“实时代码监控”
人工智能·spring boot·python·ai编程
lucky67077 小时前
Spring Boot集成Kafka:最佳实践与详细指南
spring boot·kafka·linq
Coder_Boy_7 小时前
基于Spring AI的分布式在线考试系统-事件处理架构实现方案
人工智能·spring boot·分布式·spring