温馨提示×

为何linux backlog丢失连接

小樊
42
2026-10-05 08:40:09
栏目: 智能运维

在 Linux 网络编程中,backlog 导致连接“丢失”(更准确说是被丢弃或无法建立)是一个经典问题,原因涉及内核参数、TCP 协议行为和应用程序处理速度。下面系统说明。


一、backlog 到底是什么?

以 listen(sockfd, backlog) 为例:

listen(sockfd, backlog);

backlog 不是“总连接数上限”,而是:

已完成三次握手、但还没被 accept() 取走的连接队列长度上限

Linux 中实际涉及两个队列:

  1. SYN 队列(半连接队列)
    • 收到 SYN,未完成握手
  2. accept 队列(全连接队列)
    • 三次握手完成,等待 accept()

backlog 主要影响 accept 队列


二、为什么会出现“连接丢失”?

1️⃣ accept 队列满了(最常见)

当:

  • 客户端完成三次握手
  • 但服务端 accept() 太慢或没调用

→ accept 队列满
→ 新完成的连接被丢弃

表现:

  • 客户端以为连接成功
  • 服务端却“看不到”
  • 客户端可能收到 RST 或超时

2️⃣ backlog 值被内核“悄悄改小”

Linux 实际队列长度:

min(backlog, /proc/sys/net/core/somaxconn)

默认:

net.core.somaxconn = 128

即使你写:

listen(sock, 1024);

实际可能只有 128

✅ 解决:

sysctl -w net.core.somaxconn=1024

3️⃣ SYN 队列满(半连接丢失)

受以下参数影响:

net.ipv4.tcp_max_syn_backlog

如果:

  • 握手风暴
  • SYN flood 攻击
  • 网络延迟大

→ SYN 被丢弃
→ 客户端重传,最终失败


4️⃣ 启用了 syncookies(隐含“丢失”)

net.ipv4.tcp_syncookies = 1

作用:防止 SYN flood
代价:

  • 不维护 SYN 队列
  • 某些情况下连接“看起来丢了”

✅ 高并发场景常见现象


5️⃣ 应用层阻塞导致 accept 不及时

例如:

  • 单线程 accept
  • accept 后做重 IO
  • 锁竞争

结果:

  • 队列瞬间打满
  • 后续连接被内核丢弃

6️⃣ 客户端超时比服务端快

即使连接“在队列里”:

  • 客户端先超时
  • 主动 RST

看起来像“连接丢失”


三、典型现象对照表

现象 可能原因
客户端超时 accept 队列满
客户端 RST 服务端丢弃连接
大量 SYN 重传 SYN 队列满
连接数上不去 somaxconn 太小
偶发失败 accept 不及时

四、如何排查?

查看队列状态

ss -lnt

关注:

  • Recv-Q
  • Send-Q

查看丢包

netstat -s | grep -i listen

内核参数

sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog

五、正确做法总结 ✅

  1. 合理设置 backlog
    listen(fd, 1024);
    
  2. 同步调大 somaxconn
  3. accept 要快(多线程 / 非阻塞)
  4. 监控队列长度
  5. 避免阻塞式业务在 accept 线程

如果你愿意,我可以:

  • 结合 具体语言(C / Java / Go)
  • 或 压测场景
  • 或 内核版本

给你更针对性的建议。

0 踩