SpringBoot响应式SSE实时推送,吞吐10万
单机下能稳定维持十万级以上的并发长连接,平均响应保持在五十毫秒以内,CPU 占用不超过七成,堆内存小于 3GB,单条消息推送延时控制在 100ms 以内,连续一小时连接不掉线。这是用 Spring Boot + WebFlux 搭配 SSE 做高并发实时推送时,一次压测能拿到的成绩。听起来有点厉害,但这就是实测数据,不是空口号。

先说最直接的东西:用 SSE(Server-Sent Events)加上 WebFlux,这套组合在单向推送场景里比 WebSocket 更省资源。SSE 走的是 HTTP 长连接,服务器单向把数据推给客户端,不需要双工通信,省掉不少握手和来回。WebFlux 自身是非阻塞的事件循环模型,能把大量长连接放在很少的线程上处理,和传统基于 Servlet 的 Spring MVC 比,差别挺明显。Spring MVC 每个请求都占一个线程,线程有上限(默认约 200),这直接限制了连接数,短请求、同步任务还能凑合,长连接场景撑不住。WebFlux 用 Reactor,采用非阻塞 IO,适合异步的长连接和流式处理,连接数可以大幅增加,理论上能做到百万级别,实操受限于系统资源,但突破十万并不稀奇。
把具体的对比说清楚:SSE 是单向的(服务器往客户端推),基于 HTTP,能复用 80/443 端口,和代理、现有架构好衔接。WebSocket 是双向的,需要额外的握手和独立的协议,常常需要开新的端口,资源消耗更高。并发承载方面,SSE 在非阻塞模型下更省空间;WebSocket 由于双向通信,资源占用更高,适合聊天、实时协作这种必须双向的场景。换句话说,你只是想发通知、推行情或日志流,SSE 更合适;要实时互动,那就选 WebSocket。
回到实现层面。把用户和各自的 SSE 连接管理好,是系统能不能撑住并发的关键。做法一般是用一个线程安全的 Map 存用户 ID 到连接的映射,支持连接注册、移除,还有批量推送。接口上要提供一个建立连接的端点(客户端通过 EventSource 建立并监听),以及一个用于测试或触发推送的接口。服务端用 WebFlux 返回 Flux>,把消息流塞进去。客户端不用额外依赖,浏览器里的 EventSource 就能直接用,这点很方便。
不过默认的 JVM、Netty、操作系统参数不能直接支撑十万级长连接。要改配置:调整 Linux 内核关于文件描述符的限制(每个连接会占一个 fd),调大 epoll 的队列、优化 Netty 的线程和内存分配,合理设置连接超时和心跳机制,避免大量死连接耗资源。压测也不能靠浏览器扛。常用的方法是用 JMeter 写 SSE 的脚本,或者用 wrk 配合 Lua 自定义脚本去模拟大量 EventSource 客户端。实际压测里,按照上面调整并发到 100k+,平均响应
集群环境下会遇到用户连接路由的挑战。每台机器都持有连接,如果要向某个用户推送消息,系统要知道该用户当前连接在哪台机器,或者把消息广播到所有节点再由节点筛选。常见做法是用一致性哈希或聚焦式路由表,也有把消息在节点间传递的中间层。对大量用户推送同一条消息时,可以减少单条 next() 调用频率,采取批量打包,列如每 100ms 聚合一次再一起发,能明显降下 FluxSink 的压力。注意别让恶意连接占满资源,生产环境中要验证用户身份,限制每个用户的连接数,防止被攻击。
实现细节上还有几件事必须写进代码里:连接生命周期管理、异常恢复策略、心跳检测和断线重连策略。连接建立接口返回的是一个不断推送的 Flux,连接被移除要及时从 Map 清掉,避免内存泄漏。批量推送时要思考序列化和压缩,减少网络负载。测试用例要覆盖瞬时大量连接建立和大量消息同时推送这两种极端场景。实测中把消息推送延迟控制在 100ms 以内,系统能够处理的消息吞吐量和连接稳定性都比较优秀,这是靠这些细节打下来的。
再说一下依赖和配置。项目需要引入
spring-boot-starter-webflux,WebFlux 原生支持 SSE,不需要额外的 SSE 库。这点挺好,少了外部依赖。Netty 是底层网络组件,许多 WebFlux 的默认实现就是基于 Netty。JVM 参数方面要注意堆外内存和 GC 策略,不要让 GC 在高并发时频繁触发。Linux 层面把 ulimit -n 提高到足够值,调整内核参数支持更多 socket,保证单机文件描述符够用。
关于适用场景:实时通知、行情推送、日志流、实时数据看板这些都很适合用 WebFlux + SSE。它们都是服务器向客户端单向发数据的场景,不需要客户端频繁发回大量信息。在这些情况下,SSE 比 WebSocket 更轻、更省资源。反过来,像在线聊天、多人协作那类需要双向交互的应用,就别用 SSE,改用 WebSocket 或者结合 WebRTC 等技术。
压测指标要记录清楚,方便对比。列如并发连接数、平均响应时间、CPU 和内存占用、消息推送延迟、连接稳定性。用 JMeter 或 wrk 做压测时,把这些指标在不同并发级别下拿出来对比,可以看出瓶颈在哪儿。单机并发极限受制于文件描述符和内存,集群部署时还要思考连接分配和路由策略。
最后补一两句个人感想:用 WebFlux + SSE 把“用很少的资源推许多人”的事儿做成了现实,对运维要求比传统方式高些,但收益明显。配置和代码都要细心打磨,压测得彻底,别光看概念。若场景需要双向通信,那就别勉强用 SSE,直接选能双工的方案比较稳。




