NAT 会话超时与长连接断开:SSH 闲置卡死、数据库连接失效、WebSocket 掉线的原因与对策
做运维和开发的人几乎都遇到过:SSH 登录服务器后去开了个会,回来敲命令毫无反应,过一会儿才弹出「client_loop: send disconnect: Broken pipe」;应用服务器连着数据库,夜里没有请求,第二天早上第一批请求全部报错「MySQL server has gone away」或者「Communications link failure」;网页上的 WebSocket 连接放着不动,几分钟后消息就收不到了,刷新才恢复。
这些现象的共同点是:连接闲置了一段时间,期间没有任何数据包经过。家里的路由器、公司的防火墙、运营商的大型 NAT 设备都要为每条连接维护一条会话记录,记录里写着内网地址与公网端口的对应关系。记录不能无限保留,闲置超过一定时间就会被删除。删除之后,两端都不知道,下一个数据包到了 NAT 设备找不到对应记录,只能丢弃或回一个重置。理解了这一点,解决办法就很清楚:让连接定期发一点数据,别让它闲到被删。
常见设备的会话超时差异
表中的数值只是常见范围,具体以各设备的实际配置为准。关键在于:一条连接要经过很多台设备,只要其中任何一台的超时最短,它就决定了连接能闲置多久。家里宽带如果是运营商级 NAT(没有独立公网地址),或者用手机流量,闲置超时往往只有几分钟,比自家路由器短得多,而这部分完全由运营商控制。所以靠调大超时只能解决自己能控制的那一段,最可靠的办法是在两端加保活。
| 设备类型 | TCP 闲置超时 | UDP 闲置超时 | 能否调整 |
|---|---|---|---|
| Linux 内核默认 | 已建立连接可保留数天 | 几十秒到数分钟 | 可通过内核参数调整 |
| 家用路由器 | 因固件而异,常见数十分钟到数小时 | 常见数十秒到数分钟 | 部分固件可调 |
| 运营商级 NAT | 通常更短,且不透明 | 通常更短 | 用户无法调整 |
| 手机移动网络 | 常见较短,省电策略更激进 | 较短 | 用户无法调整 |
| 企业防火墙 | 按安全策略设定,常见一小时左右 | 按策略设定 | 需找管理员 |
| 云平台负载均衡 | 多有固定的闲置超时 | 按产品设定 | 部分可在控制台调整 |
从定位到解决:分步操作
- 第一步:先把网络线路准备好。如果要连的服务器在海外,先连上刺猬VPN并固定一个节点再开始测试,避免把切换节点造成的断线误认为 NAT 超时;自定义用户名和密码即可匿名注册,不需要邮箱、不需要手机号,免费节点永久免费、不限流量、不限速;
- 第二步:确认断线规律。记录连接闲置多久后会断,如果总是闲置差不多的时间后断开、有数据时从不断,基本可以判断是会话超时;随机断开则更可能是线路质量问题;
- 第三步:SSH 客户端加保活。在本机的 SSH 配置文件里为对应主机加上 ServerAliveInterval 60 与 ServerAliveCountMax 3,客户端每六十秒发一个保活包,连续三次无响应才断开;
- 第四步:SSH 服务端加保活。在服务器的 sshd 配置里设置 ClientAliveInterval 60 与 ClientAliveCountMax 3,重启 sshd 后生效,两端都设置更保险;
- 第五步:调整系统的 TCP 保活参数。Linux 默认在连接闲置两小时后才发第一个保活探测,远超大多数 NAT 的超时,可以把 net.ipv4.tcp_keepalive_time 调到 600 甚至更短,前提是应用开启了 TCP 保活选项;
- 第六步:数据库连接池设置。连接池的最大存活时间要短于中间设备的闲置超时,并开启定期的保活或校验查询,让连接池主动替换可能已失效的连接,而不是等业务请求撞上去才报错;
- 第七步:WebSocket 加应用层心跳。浏览器与服务器之间每隔二三十秒互发一次心跳消息,服务端用 ping 帧、前端收到后回应,超过两三次没有回应就主动重连;
- 第八步:路由器上调整会话超时。OpenWrt 等固件可以通过 net.netfilter.nf_conntrack_tcp_timeout_established 等参数调整,调大能减少断线,但会占用更多会话表空间,设备内存小的不要调得过大;
- 第九步:验证效果。修改后让连接闲置超过原来断开的时间,再发送数据,确认连接仍然可用,再把配置同步到其他服务器与客户端。
按现象排查
长连接断开的报错五花八门,下面把常见的报错和对应的原因放在一起,方便对号入座。
- SSH 闲置后报「Broken pipe」:会话记录已被删除,客户端发数据时被重置,加 ServerAliveInterval;
- SSH 闲置后卡住不动、很久才断:中间设备直接丢弃数据包而不回重置,客户端要等重传超时才发现,同样靠保活解决;
- 数据库报「server has gone away」或「Communications link failure」:连接池里的连接闲置被中间设备或数据库自身断开,缩短连接最大存活时间并开启校验;
- PostgreSQL 报 SSL SYSCALL error: EOF detected:连接在传输层被中断,常见于闲置后的第一次查询,处理方式同上;
- WebSocket 闲置几分钟后收不到消息:会话被删除但浏览器不知道,加应用层心跳与自动重连;
- 手机上的推送和即时消息延迟:移动网络的闲置超时更短,应用需要更频繁的心跳,系统省电策略也会影响;
- 只有晚上或只有某个网络下才断:可能是运营商的 NAT 策略或线路拥堵,换网络对比测试;
- 加了保活仍然随机断开:问题可能不在 NAT,而在线路质量或服务端重启,查看两端日志确认。
线路与客户端怎么选
线路本身也是一条长连接,同样要穿过家里的路由器与运营商的 NAT。保持一个固定节点、不频繁切换,能减少因为线路重建导致的上层连接中断。客户端的断线保护会在线路异常时先阻断流量,避免请求从直连出去造成会话错乱,线路恢复后上层应用再按自己的重连逻辑恢复。刺猬VPN的「不限速」只表示不对账号设速率上限,实际稳定性受本地网络与运营商策略影响。
| 对比项 | 免费节点 | 时长套餐 | 流量包 |
|---|---|---|---|
| 适合场景 | 偶尔连海外服务器排查 | 每天远程运维与开发 | 短期项目 |
| 流量规则 | 永久免费、不限流量 | 有效期内不限流量 | 用多少扣多少,到期未用完清零 |
| 速度规则 | 不限速 | 不限速 | 不限速 |
| 节点选择 | 以免费节点列表为准 | 可固定负载较低的会员节点 | 可选会员节点 |
| 断线保护 | 支持 Kill Switch | 支持 Kill Switch | 支持 Kill Switch |
| 多设备 | 一个账号多设备在线 | 一个账号多设备在线 | 一个账号多设备在线 |
保活间隔怎么定
保活间隔太长,起不到作用;太短,又会增加无谓的流量与电量消耗,手机上尤其明显。一个实用的经验是:间隔取路径上最短闲置超时的一半左右。不知道具体超时时,可以从六十秒开始,如果仍然断开就缩短到三十秒;手机等移动场景可以从二三十秒开始尝试。服务器端面对大量客户端时,心跳间隔还要考虑整体负载,几万个连接每十秒一次心跳也是不小的开销。
还要注意区分两种保活。TCP 层的保活由操作系统发送,应用无感知,但只能证明对方的系统还在,不能证明应用正常;应用层心跳由程序自己发送,能同时检测应用是否卡死,适合 WebSocket、即时通信与游戏。两者可以同时使用,TCP 保活兜底,应用心跳负责及时发现问题并重连。
用抓包确认会话已被删除
想确凿地证明是 NAT 超时,可以在客户端用抓包工具观察。让连接闲置到超过怀疑的超时时间,然后发送一条数据:如果看到数据包发出后立即收到对方的重置,或者连续重传多次都没有任何回应,同时服务器端的抓包里根本没有收到这条数据,就说明数据包在中间被丢掉了,会话记录已经不存在。
反过来,如果服务器端收到了数据却没有回应,问题就在服务器上,比如进程卡死或者防火墙规则。把客户端与服务器两端的抓包结果放在一起看,问题出在哪一段一目了然,也方便拿着证据去找网络管理员或运营商沟通。
和其他断线问题的分工
WebSocket 断线除了 NAT 超时,还可能来自反向代理的读超时、负载均衡的闲置超时与前端页面切到后台被节流,完整的排查顺序见 WebSocket 频繁断开排查,本文的心跳设置可以直接配合使用。
如果断开的是线路本身,比如客户端频繁提示重连、隔一阵就掉线,原因可能是网络切换、系统休眠、节点负载或本地防火墙,见 VPN 经常断开怎么办。先判断断的是上层应用连接还是线路本身,再选对应的处理方法。
常见报错速查表
| 现象 | 原因 | 解决办法 |
|---|---|---|
| SSH Broken pipe | 闲置后会话记录被删 | 客户端设置 ServerAliveInterval |
| SSH 卡住很久才断 | 中间设备静默丢包 | 两端都开启保活 |
| server has gone away | 连接池连接闲置失效 | 缩短最大存活时间并开启校验 |
| SSL SYSCALL error: EOF detected | 传输层连接被中断 | 连接池保活与重试 |
| WebSocket 闲置后收不到消息 | 会话被删除 | 应用层心跳与自动重连 |
| 只在移动网络下断 | 移动网络超时更短 | 缩短心跳间隔 |
高频问答
- 问:怎么判断是不是 NAT 超时?答:看规律,总是闲置差不多时间后断、有数据时从不断,基本就是会话超时;
- 问:调大路由器的超时能彻底解决吗?答:只能解决自家路由器这一段,运营商的 NAT 无法调整,保活才是根本办法;
- 问:TCP 保活默认不就开着吗?答:很多应用默认不开启,开启了的默认间隔也是两小时,远超 NAT 超时;
- 问:心跳会不会很耗流量?答:每次心跳只有几十字节,间隔合理时流量可以忽略,手机上主要考虑电量;
- 问:开着线路会让问题更严重吗?答:线路也要穿过 NAT,固定节点、不频繁切换能减少中断;
- 问:云服务器的负载均衡也会断吗?答:会,多数负载均衡有固定的闲置超时,需要按产品文档设置心跳。
让长连接真正长下去
NAT 会话超时导致的长连接断开,本质是中间设备在连接闲置时删除了会话记录,两端却毫不知情。先通过断线规律确认原因,再在 SSH、数据库连接池、WebSocket 等各层加上保活或心跳,能调整的路由器适当调大超时,保活间隔取最短超时的一半左右,大部分「放一会儿就断」的问题都会消失。
刺猬VPN采用 HTTPS+AES 加密传输,支持自定义用户名和密码匿名注册,不需要邮箱和手机号;免费节点永久免费、不限流量、不限速,适合偶尔连接海外服务器排查问题;时长套餐有效期内不限流量、不限速,适合每天远程运维与开发,客户端带断线保护与按域名分流,一个账号支持多设备同时在线。各设备的超时数值以实际配置为准,实际可用性取决于当前网络环境。
开始使用刺猬VPN:HTTPS+AES 加密、零日志,匿名注册无需邮箱
刺猬VPN提供永久免费节点,不限流量;无需邮箱,自定义用户名即可匿名注册。一个账号支持多设备同时在线,实际可用性取决于当前网络环境。