为什么你的应用需要长连接网关?与NLB TCP
我的处理经验
如果你正在处理NLB TCP,先别急着照搬网上的参数。很多业务场景下,客户端和服务端之间需要保持一条长时间的通信通道,而不是每次请求都新建、销毁连接。典型的例子包括:
- 消息推送(如即时通讯、股票行情)—— 服务端需要主动推送数据给客户端;
- 游戏对战(尤其实时竞技类)—— 玩家操作和状态同步要求低延迟、高频率;
- 物联网设备上报—— 设备长期在线,定期上传传感器数据或者接收指令。
对于这些场景,如果使用 HTTP 短连接,每次建立连接(TCP 三次握手、可能还有 TLS 握手)会消耗额外的 2~3 个 RTT,同时服务端需要频繁创建与销毁 socket 文件描述符,CPU 和内存开销都很大。当并发量上升到万级、十万级,操作系统内核甚至会出现 TIME_WAIT 堆积,端口耗尽,最终导致拒绝新连接。
解决思路就是让连接“复用”——客户端和服务端建立一次连接后,双方不断发送心跳包保活,数据随意在上面传输,这就是长连接。而网关作为流量的集中入口,必须能够高效地承载和管理这些长连接。
关联教程:此处可内链到“NLB TCP部署与验证”内容。
传统常用方案的问题
配置前的检查
早期很多团队用 Nginx 或 HAProxy 做四层代理,配合 keepalived 实现高可用。但对于公有云环境,自行维护这些组件会遇到几个痛点:
- 单点瓶颈—— 软件负载均衡器本身受限于虚拟机配置,单机处理能力有限;
- 运维复杂—— 需要手动配置防火墙、ACL、健康检查脚本,升级内核参数;
- 弹性差—— 流量突增时无法快速横向扩展,通常需要预先留出大量冗余资源。
公有云厂商推出的网络负载均衡(Network Load Balancer,NLB)正是为了解决这些问题而设计的。它工作在 OSI 第四层(传输层),能够原生处理 TCP 和 UDP 流量,对长连接场景有原生优势。
NLB 是什么?和 ALB/CLB 有何不同?
实际操作要点
很多人会把 NLB 和 ALB(应用负载均衡)或 CLB(传统负载均衡)混淆。简单说:
- ALB(应用型)—— 工作在第七层,可以理解 HTTP/HTTPS 协议头,支持基于域名、路径、Cookie 的转发。但它对 TCP/UDP 长连接并不友好,因为它会中断客户端连接,再建立一条到后端的新连接,导致源 IP 被隐藏,连接状态也被终止。
- CLB(传统型)—— 通常也支持四层转发,但实现上多基于代理模式,和后端之间是“两次连接”,仍然存在中间状态。
- NLB(网络型)—— 走的是直接路由(DSR)或者全透明代理架构。它不修改 IP 报文,只根据五元组(源 IP、源端口、目的 IP、目的端口、协议)做哈希分发。客户端发送的 TCP SYN 到达 NLB 后,NLB 直接转发给后端服务器,后端服务器直接回复客户端,整个过程就是一次连接,客户端看到的源 IP 就是 NLB 的 VIP,后端服务器能看到真实的客户端 IP(如果开启 TOA 等选项)。
正是因为 NLB 不做协议解析、不修改报文、不建立中间连接,它的性能瓶颈极低,一台 NLB 实例可以轻松支撑数百万并发连接,延迟也只有微秒级。
NLB 优化长连接网关的关键参数
虽然 NLB 本身很强,但如果后端服务器或者客户端配置不当,依然会耗尽资源。以下是生产环境中需要重点关注的几个方面:
1. 会话保持(Session Persistence)与连接一致性
对于长连接场景,一个客户端从连接到断开都希望落在同一台后端服务器上(状态信息可能存本地内存,比如游戏房间)。NLB 默认基于五元组哈希,只要客户端 IP、端口不变(保活期间通常不变),同一连接永远会打到同一台服务器。但要注意如果客户端经过 NAT,源 IP 会变化,需要配置 NLB 的源 IP 会话保持功能(一般基于源 IP 哈希,超时时间建议设置大于心跳间隔)。
2. 健康检查的细粒度调优
NLB 的健康检查可能使用 ICMP、TCP 或 UDP 探测。对于长连接网关,建议使用TCP 三次握手探测(connect 端口),而不是只 ping。因为端口监听正常不代表业务进程正常。健康检查间隔不宜过短(默认 5 秒通常足够),否则频繁探测本身也会消耗连接资源。如果后端进程启动较慢(比如 Java 应用),需要调大健康检查超时时间和不健康阈值,避免 NLB 误判。
3. 连接超时与闲置断开
NLB 本身会跟踪四层连接的状态。对于 TCP 长连接,如果客户端长时间不发数据,NLB 默认会在 60~300 秒(各云产商不同)后主动断开连接(发送 RST)。如果业务心跳间隔比这个值大,客户端连接就会被误杀。此时需要在 NLB 配置中调大空闲连接超时时间,或者确保客户端心跳间隔小于该超时时间。
4. 后端服务器的内核参数
后端服务器需要承受百万级长连接,必须调整内核参数:
net.ipv4.tcp_keepalive_time:减小到 120 秒左右,让内核在应用层心跳失效时快速回收僵尸连接。net.ipv4.tcp_tw_reuse和tcp_tw_recycle:开启reuse,不开启recycle(NAT 环境有风险)。net.core.somaxconn:放大到 65535,提升 accept 队列长度。net.ipv4.ip_local_port_range:扩大客户端可用端口范围,如10240 65535。
5. MTU 与 MSS 钳制
长连接经常传输小数据包,如果网络路径中有较小 MTU(如 VPN 或隧道),容易导致分片或丢包。NLB 通常支持 MSS 钳制,可以将 TCP 报文最大分段大小强制设为 1460 或更小,避免 IP 分片。
部署架构实践:从 0 搭建一个高并发长连接网关
我的处理经验
假设你的业务是物联网设备接入,设备每次上报只需几百字节,但需要保持长连接随时接受指令。以下是在某公有云上的典型步骤:
- 创建 NLB 实例:选择地域,实例规格选“小型”即可(云厂商一般按每秒新建连接数、并发数等指标定价),并开启“IP 类型转发”(支持客户端直接看到源 IP)。
- 配置监听器:协议选 TCP,端口 8080(自定义)。关闭“保持客户端源 IP”的兼容模式(否则可能影响性能)。
- 添加后端服务器组:选择多台 ECS(建议偶数台,避免哈希不均),设置权重。健康检查使用 TCP:8080,间隔 5 秒,超时 3 秒,健康阈值 2,不健康阈值 3。
- 调整后端服务器内核:登入每台 ECS,执行
sysctl -w net.ipv4.tcp_keepalive_time=120等参数,并永久写入/etc/sysctl.conf。 - 测试连接:用 netcat 模拟客户端连接,观察是否在 NLB 空闲超时(比如 300 秒)后自动断开,如果断开则调大 NLB 超时。
- 压力测试:使用
wrk或tcpreplay模拟数万连接,监控后端服务器 CPU、内存、连接数(ss -s)。
实际部署时还可以结合 Auto Scaling:监控后端服务器组的 CPU 平均利用率或连接数,当连接数超过阈值自动扩容 ECS 数量,NLB 会自动将新连接分发到新机器。
延伸阅读:此处可内链到“NLB TCP配置案例”相关文章。
想继续深入:此处可内链到“NLB TCP优化清单”文章。
进阶阅读:此处可内链到“NLB TCP性能优化”指南。
NLB TCP:常见踩坑与排查思路
故障定位思路
- 连接总是断开:检查 NLB 空闲超时是否太小,或者客户端心跳间隔大于超时值。
- 后端看不到真实客户端 IP:确认 NLB 是否支持并开启了 TCP Option Address (TOA),如果后端是容器环境可能不支持,需要用 proxy protocol。
- 新连接失败:查看后端
ss -t确认是否 socket 队列满(Recv-Q或Send-Q非零),调大net.core.somaxconn。 - UDP 长连接注意:UDP 无状态,NLB 的会话保持需要基于源 IP + 源端口哈希,如果客户端端口经常变化,会导致后端分布不均,建议使用类似 QUIC 的 connection ID 做路由。
相关阅读:此处可内链到“NLB TCP常见问题”专题。
总结
验证与回滚
公有云 NLB 是承载高并发 TCP/UDP 长连接网关的最佳起点。它硬件加速、弹性伸缩、开箱即用,免去了自建集群的运维烦恼。但长连接优化不止依赖负载均衡器本身,还需要后端服务器正确配置内核参数、合理设置心跳与超时,以及配合健康检查与弹性伸缩策略。希望本文能帮你扫清概念盲区,在实际项目中少走弯路。把这些步骤跑通后,NLB TCP基本就能稳定落地。
延伸阅读
