4. TCP连接超时:三次握手阶段的隐形杀手
TCP连接超时,说白了就是客户端发出的SYN包石沉大海,或者服务器回了SYN-ACK但客户端没收到。这是TLS握手失败里最常见、也最让人头疼的一类问题。我个人习惯把这类问题分成两类:SYN队列满和iptables规则拦截。今天咱们就一个一个拆开看。
4.1 SYN队列满:服务器忙不过来
先说说SYN队列。服务器收到客户端的SYN包后,不会立刻建立连接,而是先把这条半连接扔进一个叫「SYN队列」(也叫半连接队列)的地方。等三次握手完成,再移到「Accept队列」(全连接队列)。
为什么会满?说白了就是服务器处理不过来。比如突发的DDoS攻击,或者正常的业务流量高峰,都会让SYN队列爆掉。我记得有一次帮一家电商平台排查问题,双十一凌晨流量突然飙升,结果大量用户反馈App卡在登录界面。一查,SYN队列满了,新来的SYN包直接被丢弃。
核心判断方法:
- 用
netstat -s | grep -i "listen"看是否有SYN to LISTEN sockets dropped - 用
ss -lnt看Recv-Q是否持续大于0 - 用
cat /proc/net/stat/synproxy看SYN代理的统计
嗯,这里要注意:SYN队列满不一定会立刻丢包。Linux内核有个机制叫「SYN Cookie」,当SYN队列快满时,内核会自动启用SYN Cookie来缓解压力。但SYN Cookie也有代价——它会禁用一些TCP选项,比如时间戳、窗口缩放等,可能影响长连接性能。
4.2 iptables规则拦截:看不见的墙
另一种常见情况是iptables规则把SYN包给拦了。你想想看,服务器配置了严格的防火墙规则,比如只允许特定IP段的访问,或者限制了每秒新建连接数。一旦规则配置不当,正常的TLS握手请求就会被静默丢弃。
我曾经遇到过一个问题:客户反馈某个地区的用户总是连不上服务,但其他地区正常。排查了半天,发现是运维在iptables里加了一条针对该地区IP段的限速规则,限速值设得太低,导致正常的SYN包也被丢掉了。
排查技巧:
- 用
iptables -L -n -v查看规则匹配计数,看是否有规则命中数异常高 - 用
tcpdump -i any port 443 -c 100抓包,看SYN包是否到达服务器 - 检查
conntrack表是否满了:cat /proc/sys/net/netfilter/nf_conntrack_max
4.3 两种场景的对比
| 特征 | SYN队列满 | iptables拦截 |
|---|---|---|
| 客户端现象 | 连接超时,偶尔能连上 | 持续超时,完全连不上 |
| 服务器日志 | 无明确错误,可能看到丢包统计 | 无日志,包被静默丢弃 |
| 抓包特征 | SYN发出后无响应 | SYN发出后无响应,或收到RST |
| 排查方向 | 检查SYN队列大小、SYN Cookie状态 | 检查iptables规则、conntrack表 |
4.4 解决思路与实战操作
先说SYN队列满的解法。最直接的办法是调大SYN队列长度:
# 查看当前SYN队列大小
sysctl net.ipv4.tcp_max_syn_backlog
# 临时调大(建议根据内存情况调整)
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
# 永久生效
echo "net.ipv4.tcp_max_syn_backlog=4096" >> /etc/sysctl.conf
sysctl -p
但光调大队列不够,还得配合SYN Cookie:
# 确保SYN Cookie开启
sysctl -w net.ipv4.tcp_syncookies=1
# 调整SYN-ACK重试次数(默认5次,建议改为3次)
sysctl -w net.ipv4.tcp_synack_retries=3
注意:调大SYN队列会占用更多内存。如果服务器内存紧张,优先考虑开启SYN Cookie和优化应用层处理速度,而不是无脑调大队列。
再说iptables拦截的解法。我建议先确认是哪条规则在作怪:
# 查看规则匹配计数
iptables -L INPUT -n -v --line-numbers
# 如果发现某条规则匹配数异常高,先临时放行测试
iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT
# 确认问题后,再调整具体规则
# 比如调整限速规则
iptables -R INPUT 5 -p tcp --dport 443 -m limit --limit 1000/s -j ACCEPT
另外,别忘了检查conntrack表。我曾经遇到过conntrack表满了导致新连接被丢弃的情况:
# 查看当前conntrack使用量
cat /proc/sys/net/netfilter/nf_conntrack_count
# 查看最大限制
cat /proc/sys/net/netfilter/nf_conntrack_max
# 如果快满了,可以调大
sysctl -w net.netfilter.nf_conntrack_max=262144
4.5 核心知识体系
下面这张图总结了TCP连接超时的根因和排查路径,我建议你收藏起来,遇到问题时对照着看:
4.6 避坑指南
最后分享几个我踩过的坑:
- 不要只调大SYN队列而不开SYN Cookie——我曾经这么干过,结果内存被吃光,服务器直接OOM。
- iptables规则顺序很重要——规则是从上到下匹配的,放行规则要放在拒绝规则前面。我见过有人把拒绝规则放在最前面,结果所有流量都被拦了。
- conntrack表满了不会报错——它只会静默丢包。如果你发现连接超时但iptables规则没问题,记得查一下conntrack。
- 调优参数要配合业务场景——比如短连接场景(像HTTP API)需要更大的SYN队列,长连接场景(像WebSocket)则更需要调大Accept队列。
嗯,TCP连接超时这块内容不少,但核心就两点:要么是服务器忙不过来,要么是防火墙拦住了。掌握了排查思路和调优手段,大部分问题都能在10分钟内定位。下次遇到类似问题,记得先抓包看看SYN包的状态,别一上来就怀疑TLS证书配置。