首页 >  文章 >  linux

Linux 端口连接堆积怎么查:ss 的 SYN-RECV、TIME-WAIT 与监听队列

来源:17golang原创

时间:2026-08-16 12:51:28 321浏览 收藏

线上服务出现偶发连接超时的时候,先别急着把锅全甩给带宽,也别上来就把所有TCP参数往大了调。Linux里 LISTENSYN-RECVTIME-WAIT 都看起来像“连接数很多”,但它们对应的TCP阶段完全不一样:有的是应用正在等待接收请求,有的是三次握手还没走完,有的是连接已经关闭、正等着系统回收资源。先用 ss 把不同连接状态拆开统计,再看监听队列和应用的 accept 速度,调参才不会漏掉真正拖慢服务的慢消费者。

要点速览
  • ss -lnt 的监听行里,Recv-Q 更接近当前已经完成握手的待消费连接队列长度,Send-Q 就是当前监听队列的最大上限。
  • SYN-RECV 持续增长说明半连接请求出现积压,TIME-WAIT 数量偏高大多是短连接关闭后的资源回收压力。
  • somaxconntcp_max_syn_backlog 分别约束已完成连接和半连接请求的容量,最终实际生效的上限还会受应用自身配置的 backlog 影响。
  • 只有明确确认队列已经溢出之后,才去调大对应参数;调整完必须复查 ss、内核统计计数和业务侧的连接成功率。

Linux 用 ss 区分 LISTEN、SYN-RECV 和 TIME-WAIT 连接状态及监听队列

先用 ss 判断连接到底堵在哪一段

假设业务服务监听的端口是 8080,先跑命令保留一份纯数字化、不会触发额外DNS解析的现场快照:

sudo ss -lnt sport = :8080
sudo ss -ant state syn-recv sport = :8080
sudo ss -ant state time-wait dport = :8080

第一条命令看监听套接字的队列占用情况,第二条统计还停留在半连接阶段的请求,第三条观察已经走完关闭流程但还没释放的连接。不要只执行一次就下判断,连续采样10秒左右拿到的波动数据参考价值更高:

for i in 1 2 3 4 5; do
  date '+%T'
  ss -lnt sport = :8080
  ss -ant state syn-recv sport = :8080 | tail -n +2 | wc -l
  ss -ant state time-wait dport = :8080 | tail -n +2 | wc -l
  sleep 2
done

如果监听行的 Recv-Q 持续接近 Send-Q,同时 SYN-RECV 数值还在快速上涨,优先怀疑是应用来不及接收新连接,或者刚好遇上突发流量打满了队列。要是 TIME-WAIT 数量很高但监听队列占用一直稳定,排查方向就该转向短连接占比、客户端连接复用策略和连接关闭的节奏,不用上来就改系统的 backlog 参数。

LISTEN 行的两列数字分别说明什么

监听套接字的 ss 输出大概长这样:

State  Recv-Q Send-Q Local Address:Port  Peer Address:Port
LISTEN 384    4096   0.0.0.0:8080       0.0.0.0:*

这里的 Recv-Q 可以直接理解为内核已经帮你完成三次握手、等着应用进程取走的已完成连接数量,Send-Q 是当前这个监听端口的队列最大上限。它既不是网卡的收发字节统计,也不是服务上已经建立好的全部TCP连接总数。如果应用的业务线程卡在数据库查询、锁等待或者启动慢初始化逻辑上,连接就会全都堆在内核队列里;单纯把队列上限从4096改成8192,只会延后连接被拒绝或者超时的时间,根本解决不了应用消费慢的根因。

现场现象优先核对的证据第一步操作
LISTEN 状态的 Recv-Q 数值接近 Send-Qss -lnt、accept 调用延迟检查消费线程状态、锁等待情况和突发流量特征
SYN-RECV 数量短时快速上涨ss state syn-recv、内核协议栈计数区分是正常握手未完成、合法流量突增还是异常攻击流量
TIME-WAIT 数量高但监听队列稳定ss state time-wait、连接复用率优化长连接保活配置和连接的生命周期管理

SYN-RECV 和 TIME-WAIT 不是同一种“连接太多”

SYN-RECV 表示本机已经回复了SYN包,还在等待对端回包完成三次握手。它占用的是半连接请求的存储槽位;大量出现的时候,可能是对端到本机的网络有丢包,也可能是服务处理速度跟不上新连接的速度。内核文档里把 tcp_max_syn_backlog 定义为每个监听器能够留存的 SYN-RECV 请求最大数量,所以它和全局配置的 somaxconn 不是同一个调节参数。

TIME-WAIT 出现在连接主动关闭之后,作用是避免旧连接的遗留报文影响后续新建立的同名连接。它本身完全不等同于监听队列溢出。先排查清楚是哪一端在主动关闭连接、客户端是不是每次发请求都新建一个TCP连接,再决定要不要调整连接池配置或者长连接保活策略。

sudo nstat -az | rg 'Listen|Syncookie|TCPAbort|TW'
sudo ss -tan state time-wait '( sport = :8080 or dport = :8080 )' | head -20

内核统计的计数器名称会随内核版本和工具版本略有差异,命令输出要以当前本机实际显示的字段为准。重点要观察参数调整前后,是否还有 listen overflow、SYN cookie 生成或者异常终止这类计数持续增长,不要只盯着某一个瞬时的连接总数做判断。

调参前同时核对 somaxconn、syn backlog 和应用 backlog

确认真的出现了队列溢出之后,先把系统当前的参数值记录下来:

sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
sudo ss -lnt sport = :8080

这几个内核参数的值,要和应用程序自身的监听配置放在一起校验。应用代码里调用 listen(fd, backlog) 函数时传入的 backlog 数值可能本身就设得很小;哪怕你把内核参数调得再大,应用也不会自动用上更大的队列上限。更稳妥的调整顺序是:先把应用实际接收连接的能力提上去,再给应用配置一个合理的backlog数值,最后在确实有明确证据的情况下再调整内核的队列上限参数。

临时验证的时候可以只挑一台灰度实例做调整,同步记录连接成功率、P99建连耗时、Recv-Q/Send-Q 比值和应用的accept调用速率。不要把所有线上机器同时改参数,不然你根本分不清问题来自流量波动还是参数改动。

Linux 监听队列溢出前后对比,展示 somaxconn、tcp backlog 与应用 accept 速率的复查关系

syncookies 只能做握手保护,不能替代合法流量的容量规划

Linux 的 syncookies 功能本来是用来在 SYN backlog 被打满的时候,缓解常见的SYN洪水攻击的,但内核文档也明确提示:如果你的告警来自合法业务的高并发流量,那还是要继续检查 tcp_max_syn_backlogsomaxconntcp_abort_on_overflow 和应用的实际吞吐能力,别把 syncookies 当成能无限扩容的开关。开启它之后可能会让部分TCP扩展特性失效,还会直接掩盖掉应用accept太慢的真实问题。

生产环境做这类配置变更,至少要提前准备好回滚方案:

sudo sysctl -w net.core.somaxconn=4096
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096
# 压测或灰度完成后,按变更记录恢复原值

如果需要把配置持久化留存,应该把参数写入经过运维管控的sysctl配置文件,走正式的发布流程审核,不要只在故障处理现场手工敲命令临时生效。全部配置做完之后,重新发起测试连接,确认监听队列占用回落、业务侧的连接成功率恢复正常。

常见问题

TIME-WAIT 数量很多,需要马上调大 tcp_max_tw_buckets 吗?

通常不需要。先确认是不是短连接比例太高、主动关闭连接的方向不合理或者连接复用率太低;只调大上限反而会掩盖连接生命周期管理不合理的潜在问题。

把 somaxconn 调大后,SYN-RECV 数量还在涨是什么原因?

somaxconn 主要影响的是已完成连接的监听队列上限,SYN-RECV 数量增长还要看 tcp_max_syn_backlog 配置、网络侧握手完成率、链路丢包情况和应用本身的accept处理速度。

ss 的 Send-Q 是网络发送缓冲区吗?

只有在已经建立连接状态的输出行里,Send-Q 才代表网络发送队列的含义;如果是在 LISTEN 状态的行里,它表示的是监听队列的最大上限。判断含义之前一定要先看清楚当前这个socket的状态。

连接超时就一定是监听队列溢出吗?

不一定。DNS解析、路由转发、防火墙规则、TLS握手开销、应用内部逻辑处理慢和上游服务的连接池耗尽都可能造成建连超时。监听队列相关的证据,只是整个故障排查链路里的其中一段。

把连接堆积排查固化成四步

遇到业务报连接超时的时候,先用 ss 分不同TCP状态做多轮采样,再把LISTEN行的两列数值和应用的accept调用速率做对应分析;只有明确确认队列已经触达上限之后,再分别核对 somaxconntcp_max_syn_backlog 与应用自身的backlog配置。调参之后再用连接成功率、建连延迟、内核统计计数和队列回落情况做多维度复查。这样得到的是完整的证据链,而不是一组碰运气试出来的sysctl参数值。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>