温馨提示×

为什么linux backlog会满

小樊
57
2026-09-02 09:11:01
栏目: 智能运维

在 Linux 网络编程中,backlog 满通常指 TCP 监听 socket 的 accept 队列(全连接队列)或 syn 队列(半连接队列)满了,导致新的连接无法被正常建立。下面从原理到常见原因系统说明。


一、先理解 backlog 是什么

以 listen(fd, backlog) 为例:

  • backlog historically:
    • 早期:同时包含半连接队列 + 全连接队列
    • 现代 Linux(2.2+):
      • backlog 主要限制 全连接队列(accept queue)
      • 半连接队列由 /proc/sys/net/ipv4/tcp_max_syn_backlog 控制

两个关键队列:

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

backlog 满,通常是 accept 队列满


二、backlog 为什么会满(核心原因)

1️⃣ 应用层 accept 太慢(最常见)

客户端完成三次握手
→ 进入 accept 队列
→ 但应用没及时 accept()
→ 队列堆积
→ 满了

典型场景:

  • 单线程阻塞 accept
  • 业务逻辑处理慢(DB、RPC、锁)
  • 线程池太小

✅ 表现:

  • ss -lnt 中 Recv-Q 接近 Send-Q
  • netstat 大量 ESTABLISHED 但未被 accept

2️⃣ backlog 设置太小

listen(fd, 5);

高并发下:

  • 每秒上千连接
  • 5 个很快满

✅ 生产建议:

listen(fd, 1024);

并结合内核参数:

net.core.somaxconn = 4096

3️⃣ 突发流量(瞬连风暴)

例如:

  • 秒杀
  • 服务刚重启
  • 客户端重试风暴

即使 accept 正常,也可能瞬时打满。


4️⃣ 客户端连接后不发送数据也不关闭

  • 连接已 ESTABLISHED
  • 占用 accept 队列
  • 应用以为“连接来了但不干活”

常见于:

  • 恶意连接
  • 客户端 bug

5️⃣ SYN 攻击(半连接队列满)

大量伪造 SYN
→ SYN 队列满
→ 无法进入三次握手

表现:

  • SYN_RECV 很多
  • 正常用户连不上

相关参数:

tcp_max_syn_backlog
tcp_syncookies = 1

6️⃣ 文件描述符 / 线程资源耗尽

即使队列没满:

  • accept() 返回 EMFILE
  • 连接卡在队列

三、如何确认 backlog 是否满

1️⃣ 查看监听队列

ss -lnt

示例:

State  Recv-Q Send-Q Local Address
LISTEN 1024   1024   :8080
  • Recv-Q ≈ Send-Q → accept 队列满

2️⃣ 查看连接状态

netstat -an | grep :8080 | awk '{print $6}' | sort | uniq -c

关注:

  • ESTABLISHED 很多但未处理
  • SYN_RECV 很多

3️⃣ 内核丢包统计

netstat -s | grep -i listen

例如:

times the listen queue of a socket overflowed

四、解决方案总结

✅ 应用层

  • 增大 backlog
  • 使用 多线程 / 异步 accept
  • 非阻塞 I/O(epoll)
  • 快速 accept,业务逻辑异步处理

✅ 系统层

net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_syncookies = 1

✅ 架构层

  • 负载均衡
  • 限流
  • 连接池
  • 服务拆分

五、一句话总结

Linux backlog 满,本质是“连接到来速度 > 应用消费速度”
要么是程序慢,要么是队列小,要么是流量异常。

如果你愿意,可以贴:

  • ss -lnt
  • 语言 / 框架(如 Nginx、Go、Java)
  • 并发量

我可以帮你精准定位是哪一种原因。

0 踩