TCP 连接断,九成不是“云服务器坏了”
云服务器上的 TCP 连接突然断开,绝大多数情况不是云厂商的物理网络故障,而是连接在某一环“超时被回收”或“资源被耗尽”:公网 NAT 会话老化、SLB 空闲超时、conntrack 表写满、文件描述符打满、带宽跑满丢包,这几个原因占了大头。先定位断在哪一层,再改配置,比盲目换机型、加带宽有效得多。
下面按“先分清是谁先动的手 → 服务端资源 → 带宽链路 → 公网与内网差异 → 续命配置”的顺序拆开讲,每一步都给可验证的命令。
云服务器 TCP 连接频繁断开,先分清是谁先动的手
连接断开在抓包里只有三种表现,指向完全不同的责任方,先花十分钟做这个区分,后面的排查能少走一大半弯路。
三种“断开”的真实含义
| 抓包表现 | 谁发起的 | 常见原因 |
|---|---|---|
| 出现 FIN / FIN-ACK 四次挥手 | 应用正常关闭 | 代码里连接用完没复用、连接池空闲回收 |
| 出现 RST 重置包 | 某一端内核或中间设备 | 进程崩溃、端口被占用、防火墙拦截、SLB 直接拒掉 |
| 双方都没包,连接静默消失 | 中间 NAT / 网关 | 会话表老化、空闲超时,两端还以为连接活着 |
第三种最容易被误判成“服务器断网”,客户端一直等,服务端也以为连接还在,直到下一次发数据才发现对端已经不可达。
三条命令锁定方向
- 抓 RST 包:
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0' -c 50,RST 大量来自服务端,问题在服务端内核或应用;来自中间地址,问题在云平台侧设备。 - 看内核统计:
netstat -s | grep -iE "reset|retransmit|overflow",重传率高说明链路在丢包,overflow 说明队列被打满。 - 看连接现状:
ss -s和ss -ant state established | wc -l,对照业务预期的并发量。
云服务器 TCP 连接数满了怎么办:从 conntrack 到文件句柄
连接数“满”不是一个原因,而是一串闸门,任何一道先到上限,新连接就会被丢掉,业内专家指出,云服务器上的连接瓶颈通常最先出现在内核的连接跟踪表和进程的文件描述符上,而不是 CPU。
conntrack 表写满,新连接直接被丢
云服务器只要用了安全组、NAT、容器网络,基本都会走 netfilter 的连接跟踪,表满之后,新连接在内核层就被丢弃,应用日志里往往什么都看不到。
- 查看用量:
cat /proc/sys/net/netfilter/nf_conntrack_count - 查看上限:
cat /proc/sys/net/netfilter/nf_conntrack_max - 看是否溢出:
dmesg | grep -i "nf_conntrack: table full" - 临时调大:
sysctl -w net.netfilter.nf_conntrack_max=262144,并同步调大nf_conntrack_buckets - 缩短老化:把
net.netfilter.nf_conntrack_tcp_timeout_established从默认的几天调到合理值,避免僵尸会话长期占坑
文件描述符和 accept 队列
ulimit -n默认常见是 1024,一个进程撑几千连接必然报Too many open files,改/etc/security/limits.conf并确认 systemd 服务的LimitNOFILE也生效net.core.somaxconn默认 128,高并发下应调到 4096 以上net.ipv4.tcp_max_syn_backlog同步调大,半连接队列溢出会导致客户端握手超时
客户端端口耗尽与 TIME_WAIT 堆积
反向场景同样常见:你的服务器作为客户端去连数据库或第三方接口,本地端口范围默认约 2.8 万个,短连接一多就耗尽。
sysctl net.ipv4.ip_local_port_range可放宽到1024 65535- 开启
net.ipv4.tcp_tw_reuse=1,配合tcp_fin_timeout缩短回收 - 更根本的办法是改用连接池,把短连接改成复用长连接
云服务器带宽跑满,TCP 连接为什么会被“挤”断
带宽打满时,TCP 不会优雅地告诉你“我堵了”,它表现为丢包、重传、RTT 飙高,重传若干次仍然收不到 ACK,内核就会判定连接失效并直接关掉,用户侧看到的就是“用着用着就断了”。
典型场景:图片站、下载服务、直播推流,出方向带宽瞬间封顶;或者被人扫接口、跑爬虫,把公网带宽吃干。
排查与处理清单:
- 云监控里看公网出/入带宽曲线,是否贴着套餐上限走
sar -n DEV 1或ifstat看网卡实时吞吐ss -tni看retrans、rtt字段,重传段数明显偏高的连接就是受害者- 业务侧做限流和排队,别让单个大文件把整条带宽吃干净
- 带宽确实不够就升级,固定带宽和按量带宽的价格结构差异较大,突发型业务用按量更划算,稳定型按固定带宽更省钱;很多套餐支持带宽包临时提额,不必急着换整台实例
云服务器 TCP 连接超时是什么原因:公网和内网是两套逻辑
同样是“连不上”或“连一会儿就断”,公网链路和内网链路的成因差别很大,行业共识认为,跨公网的连接稳定性主要受中间设备和会话老化影响,而内网更多是服务端自身资源问题。
公网侧:NAT 会话老化和负载均衡空闲超时
云上公网访问通常要过弹性公网 IP 的 NAT 和负载均衡,这些设备维护的是会话表,表项有老化时间,多数云厂商在数分钟量级,如果业务连接长时间没有数据往返,会话先被清掉,之后任何一方发包都会收到 RST 或石沉大海。
- 负载均衡的空闲超时时间各家默认值不同,一般在数十秒到数十分钟之间,业务长连接要显式调大
- 公网 NAT 的空闲老化通常不可调,只能靠保活(心跳)绕开
- 高防和清洗策略触发时会直接重置可疑连接,表现为周期性批量掉线
- 非固定公网 IP 的实例重启或变更后地址会变,客户端缓存的旧地址自然连不上
内网与公网场景对比
| 对比项 | 内网通信 | 公网通信 |
|---|---|---|
| 主要断因 | 服务端资源耗尽、进程崩溃 | NAT 老化、SLB 超时、清洗拦截 |
| 空闲容忍时间 | 可达数小时 | 通常数分钟 |
| 排查工具 | ss、dmesg、应用日志 | tcpdump、mtr、云监控 |
| 优化手段 | 调内核参数、连接池 | 加心跳、调超时、走内网或专线 |
能走内网就不要走公网,同地域内网通信的稳定性和成本都更友好,这是一条很实在的经验。
给连接“续命”:keepalive 和心跳的正确配法
既然中间设备会因为“安静”而清理会话,那就在它清理之前主动说话。
内核层 keepalive
net.ipv4.tcp_keepalive_time默认 7200 秒,太长,公网场景建议调到 300 秒以内net.ipv4.tcp_keepalive_intvl建议 15 到 30 秒net.ipv4.tcp_keepalive_probes建议 5 次以内- 应用需要在 socket 上显式开启
SO_KEEPALIVE,否则内核参数对这条连接不生效
应用层心跳
应用层心跳比内核 keepalive 更可控,也更容易观察。
- 心跳间隔设在 30 到 60 秒,小于链路上最短的老化时间
- 心跳要有超时判定和重连退避,别在网络抖动时集中重连,把服务端二次打挂
- 客户端重连加随机抖动,避免所有节点同一秒重连形成脉冲
- 服务端做连接健康检查,主动清理半开连接
验证是否生效
改完参数用 ss -tio 观察定时器状态,或者用 tcpdump 看是否周期性出现长度为 0 到 1 字节的 keepalive 包,没抓到包,说明配置没真正落到这条连接上。
Q&A:云服务器 TCP 连接断开常见疑问
云服务器 TCP 连接每 5 分钟断一次,是云厂商的问题吗?
多数情况下是链路上某个设备的老化时间在起作用,例如负载均衡默认空闲超时或公网 NAT 会话老化,先抓包确认连接是被 RST 还是静默消失,再加应用层心跳把空闲时间压到老化时间以下,基本能解决。
云服务器 TCP 连接数和带宽,哪个先成为瓶颈?
取决于业务形态,短连接、小包请求多的服务通常先撞上连接跟踪表和端口上限;大文件传输、视频类服务先撞上带宽,用 ss -s 看连接规模、用云监控看带宽曲线,两条数据一起看就能判断。
不升级带宽、不换实例,能不能提升连接稳定性?
能,改用连接池减少短连接、加应用层心跳避开 NAT 老化、调大 nf_conntrack_max 和 somaxconn、把公网调用改成同地域内网调用,这四项做完,相当一部分“莫名其妙断连”的工单会直接消失,连接稳定性的核心,是让连接的寿命短于链路上最短的那个超时时间。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/794517.html


