如何处理基于Netty的Java服务器启动时的连接突增问题
问题背景
我有一个基于Java Netty的服务器,可处理40000个长连接TLS(v1.2)连接。正常运行时2核CPU使用率仅30%,但新版本重启时,若当前有40000个活跃连接同时重连,会导致CPU长期维持100%;活跃连接少于20000个时则能正常重启。已升级到4vCPU解决问题,但希望用2vCPU实例,寻求分散连接突增的方案。
已知当前Netty默认SO_BACKLOG为4096,不确定该设为128还是1024?
要求:不考虑其他服务器SSL终止或添加负载均衡器,已使用最新版Netty、epoll和boringssl。
环境信息:
openjdk version "21.0.3" 2024-04-16 OpenJDK Runtime Environment (build 21.0.3+9-Ubuntu-1ubuntu120.04.1) OpenJDK 64-Bit Server VM (build 21.0.3+9-Ubuntu-1ubuntu120.04.1, mixed mode, sharing) Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-80-generic x86_64)
可选方案
1. 调整客户端重连策略(最核心有效)
- 给客户端添加指数退避重连逻辑:首次重连延迟1s,之后每次失败翻倍延迟(如2s、4s、8s,上限设为30s),避免所有连接同时发起重连请求。
- 加入随机抖动:在退避延迟基础上增加±20%的随机值,进一步分散重连时间点,彻底避免批量重连峰值。
2. 服务器端连接处理限流
- 动态调整EventLoop线程数:重启阶段临时将Acceptor线程数调整为与CPU核心数匹配(比如从默认1个改成2个),连接稳定后再调回原配置,提升启动阶段的连接处理能力。
- 添加握手并发限制:在Netty的
ChannelInitializer前加入自定义限流Handler,用信号量(Semaphore)控制同时处理的TLS握手数量,比如限制为500个并发握手,超出的连接暂存等待,避免CPU被密集的加密计算占满。
3. 合理设置SO_BACKLOG参数
SO_BACKLOG是TCP监听队列的大小,用于暂存未完成三次握手的连接,并非直接的限流工具:
- 设为128:队列过小会导致大量重连请求被直接拒绝,客户端需再次重连,反而增加重试次数,不建议。
- 设为1024:比默认4096小,但能在服务器来不及处理时暂存部分连接,避免直接拒绝,但无法解决CPU过载问题,需配合其他限流策略。
- 建议:保持默认4096,或根据系统
/proc/sys/net/core/somaxconn的值调整(Ubuntu 20.04默认是1024,需确保Netty的SO_BACKLOG不超过该系统值),核心还是靠限流和分散重连。
4. 渐进式开放监听
服务器启动时,先以较低的并发处理能力运行:比如前30s每秒只处理1000个连接,之后每秒递增1000,直到达到正常处理能力,平滑承接重连请求,避免瞬间压力过载。
5. 优化TLS握手CPU消耗
- 启用TLS会话复用:配置
SslContext时调整会话缓存大小,让重复连接复用之前的TLS会话,减少握手时的加密计算开销。 - 优化
EpollEventLoopGroup参数:确保使用Epoll模式(已启用),设置合理的线程数,避免过多线程上下文切换消耗CPU。
内容的提问来源于stack exchange,提问作者Dmitriy Dumanskiy
相关产品推荐
相关产品推荐

