socket-listen-overflow

服务端连接建立慢、偶发超时或 reset,ss -lnt 的 LISTEN Recv-Q 接近 Send-Q。

现象

高并发时新连接偶发超时、被重置或延迟升高,但服务进程仍在运行;ss -lnt 中监听套接字的 Recv-Q 持续大于 0 并接近 Send-Q。netstat -s 或 nstat 的 listen overflow 计数增长。

快速定位

先看监听队列深度。对 LISTEN 套接字,Recv-Q 是当前等待 accept 的连接数,Send-Q 是 backlog 上限:

ss -lnt
ss -lntp | awk 'NR == 1 || $2 > 0'
watch -n1 "ss -lnt '( sport = :8080 )'"

再看内核溢出计数器,区分 accept 队列和 SYN 队列:

nstat -az TcpExtListenOverflows TcpExtListenDrops TcpExtTCPReqQFullDrop TcpExtSyncookiesSent
netstat -s | grep -iE 'listen|overflow|SYN'
cat /proc/sys/net/core/somaxconn
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
sysctl net.ipv4.tcp_abort_on_overflow net.ipv4.tcp_syncookies

检查应用是否及时 accept:

strace -f -c -e trace=accept4 -p <PID>
ss -s

易误判:ss -lnt 的 Send-Q 是 backlog 上限,不是待发送数据;Recv-Q 短暂大于 0 只说明有连接在等待 accept,持续贴近上限才是溢出。tcp_max_syn_backlog 管 SYN 队列,somaxconn 管 accept 队列,两个计数器不同,只调一个可能无效。netstat -s 里 “SYNs to LISTEN sockets dropped”(ListenDrops)涵盖多种丢弃原因,与 “listen queue overflowed”(ListenOverflows)也不是同一个计数器。

常见根因

  1. accept 循环被阻塞:事件循环卡住、GC、同步日志/磁盘 IO 或 GIL 争用。
  2. backlog 太小:应用 listen() 传入值或 net.core.somaxconn 限制。
  3. 流量突增或连接风暴,accept 速率跟不上 SYN 到达速率。
  4. worker 数量不足,或 SO_REUSEPORT 下各监听队列分配不均。
  5. accept 后同步做 TLS 握手、鉴权或 DNS 查询,拉长每连接处理时间。
  6. 健康检查和客户端重试放大连接建立频率。
  7. tcp_abort_on_overflow=1 直接回 RST,放大失败率。
  8. SYN 队列满并触发 SYN cookies,或半连接表耗尽。

修复

相关命令

读完自测

  1. LISTEN 状态下 Recv-Q 和 Send-Q 分别代表什么?
  2. somaxconn 与 tcp_max_syn_backlog 管的是同一个队列吗?
  3. 为什么把 tcp_abort_on_overflow 设为 1 会放大故障?
答案
  1. Recv-Q 是当前等待 accept 的已完成连接数,Send-Q 是 backlog 上限。
  2. 不是;somaxconn 限制 accept 队列,tcp_max_syn_backlog 限制 SYN 队列。
  3. accept 队列满时内核直接回 RST,而不是丢弃 ACK 让客户端重传,连接失败更明显。