单机稳定支撑 10 万+长连接,平均响应时间低于 50ms,推送延迟在 100ms 以内,内存占用在 3GB 以下,CPU 使用率不超过 70%,连续运行一小时无断开。以上是压测的最终数据。

既然有了这样的成绩,先把结论的来龙去脉按时间倒过来说清楚。最后这套系统是基于 Spring Boot + WebFlux,加上 Server‑Sent Events(SSE)来做单向推送。选择的理由、改造的点、压测细节、和遇到的问题都会按步骤铺开,但顺序是从结果往前推,方便看清每一步为什么要这么做。
在压测收尾阶段,我们做了稳定性拉通:模拟 10 万并发 EventSource 客户端,持续推送,间隔按业务场景调整,有批量发送和单条推送两种模式。单机环境下,经过内核调优和 JVM/Netty 参数优化,连接存活率高,消息丢失率低。为了减少频繁触发 FluxSink.next(),对高频同体消息做了批次合并处理(列如每 100ms 把一段时间内要下发的消息打包一次),显著降低了系统负载波动。压测工具使用 JMeter 自定义脚本,并用 wrk + Lua 做补充验证。
回溯到实现层面,WebFlux 的非阻塞模型是关键。传统 Spring MVC 是基于 Servlet 的阻塞 IO,每来一个连接就占一个线程,线程池上限让长连接场景很难规模化。WebFlux 用事件循环和 Reactor,IO 不阻塞,能用更少的线程管理更多连接,这也是能跑到 10 万+的基础。由于是单向推送场景,SSE 变成更合适的协议:基于 HTTP,能复用端口且更友善代理,建立连接后服务器持续往客户端推数据,不需要像 WebSocket 那样做双向握手和维持双工通道,开销更小。
实现时遇到的三件事是必须解决的。第一,连接管理。要有线程安全的结构记录用户与对应的 SSE 连接(在 WebFlux 里就是保存对应的 FluxSink/Emitter),支持注册、注销、批量广播。第二,接口暴露。提供连接建立的端点(返回 Flux)和测试推送接口,方便运维和功能验证。第三,客户端兼容性。浏览器端原生支持 EventSource,不需要额外依赖,移动端或自研客户端也能按 EventSource 协议实现,连接建立后就能接收服务端推来的行文本事件。
系统调优环节花了不少功夫。默认的 Linux 内核文件描述符限额、JVM 堆栈和 Netty 参数都不能直接支撑十万级别长连接。于是把文件句柄上限调高,调整 epoll 相关参数,优化内核网络队列。JVM 层面优化垃圾回收策略和堆内存分配,降低 Full GC 对长连接影响;Netty 的相关 buffer、大对象复用、连接超时设置也都按高并发场景微调。除此之外,还要思考连接超时策略和心跳机制,防止那些无效或恶意连接长期占用资源。
压测流程不是一次搞定的。先是小规模验证,确认逻辑正确;接着放大到几千连接,找出瓶颈点;再到一万、三万、十万,逐步调整系统参数和部署策略。用 JMeter 写自定义的 SSE 客户端脚本去模拟真实 EventSource 行为,保障模拟结果靠得住。wrk + Lua 脚本用于补充 TCP 层面的压力测试,验证网络和内核在高并发下的稳定性。每一次扩容都监控指标:连接数、响应时间、CPU、内存、GC 突发、Netty 线程饱和度、socket 等待队列长度。最终的数字来自多次稳态观测,而不是单次峰值。
在消息分发策略上做了两条路子。对高频、对所有人都一样的消息,列如行情快照或全局告警,采用批量合并再推的方式,降低发送频率和系统调用次数。对需要准确到个人的通知,仍旧保持按用户路由单独推送。为了防止被大量非法连接拖垮,接入层做了合法性校验和滑动窗口控制,必要时能拒绝或限流异常连接。
如果业务扩展到跨机器、跨机房规模,单机能撑到 10 万只是起点。集群环境下要解决用户连接路由问题:用户在任意节点建立连接后,消息推送路由需要把消息投递到持有该用户连接的机器。常用做法是把用户-连接映射放到一致性存储或用消息总线做路由,或者在网关层做会话粘性。实践里我们在集群方案里补了两件事:一是把需要广播的消息用 pub/sub 处理,二是对点对点推送做轻量索引,避免每次都全网广播。
代码层面,依赖很简单:
spring-boot-starter-webflux 就足够,WebFlux 本身对 SSE 的支持能直接用,不需要额外引入第三方 SSE 库。服务端返回的是 Flux>,客户端通过浏览器的 EventSource 或等价实现来建立持久连接。实现示例里包含连接建立的 Controller、一个并发安全的 Map(ConcurrentHashMap)来存用户会话,以及一个批量推送的调度器,后者把短时间窗口内的事件合并后下发,减少单条调用量。
运营上还要注意两点。其一是安全和鉴权,不能让任意客户端随意连上来占用资源,鉴权流程需要在连接建立阶段完成。其二是监控埋点得细,长连接场景下单靠普通的请求监控不够,得实时看 socket 数、活跃订阅数、每秒推送量、丢包率等指标,出问题好排查。
顺序倒着说完这些技术点,顺手补一句观察:当场景只需要服务器单向下发时,用 SSE 简单、省资源,别急着把 WebSocket 当成万能钥匙。对双向交互的场景,列如实时聊天或协同编辑,才必须思考 WebSocket 或更复杂的协议。
项目的配置、压测脚本和常用的调参清单都放在仓库里,部署文档和验证步骤也记录齐全,方便后续复现和扩展。


