温馨提示×

linux backlog为何丢包

小樊
45
2026-09-08 10:23:28
栏目: 智能运维

在 Linux 网络里常说的 backlog 丢包,通常出现在 TCP 连接建立阶段(而不是数据传输阶段)。下面分场景把“为什么会丢包”讲清楚。


一、backlog 是什么

1. listen backlog 的两个队列(经典模型)

当服务端调用:

listen(fd, backlog);

内核实际上维护 两个队列

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

注意:
backlog 控制的是「全连接队列」长度(历史实现有差异)


二、为什么会“backlog 丢包”

场景 1:全连接队列满了(最常见)

过程:

  1. 客户端完成三次握手
  2. 连接进入 Accept Queue
  3. 应用没及时 accept()
  4. Accept Queue 满了
  5. 新连接被丢弃或忽略

表现:

  • netstat -s 中:
    TCPBacklogDrop
    
  • ss -lntRecv-Q 接近 Send-Q

✅ 本质:应用消费太慢


场景 2:半连接队列满了(SYN 丢)

触发条件:

  • 高并发连接
  • SYN Flood 攻击
  • tcp_max_syn_backlog 太小

表现:

  • 客户端超时重传
  • 服务端看不到连接

场景 3:backlog 参数被内核“偷偷改小”

Linux 早期:

listen(fd, 5);

实际可能是:

min(backlog, somaxconn)

查看:

cat /proc/sys/net/core/somaxconn

⚠️ 很多程序 backlog=128,但 somaxconn=128 或更小


场景 4:单进程 accept 瓶颈

即使:

  • backlog 很大
  • 队列没满

但如果:

  • 单线程 accept
  • 业务处理阻塞

仍然会:

  • 队列增长 → 最终丢包

三、如何确认是 backlog 丢包

1. 查看丢包统计

netstat -s | grep -i backlog

或:

nstat | grep -i backlog

2. 查看 listen 队列

ss -lnt

示例:

State  Recv-Q Send-Q Local Address
LISTEN 128    128    0.0.0.0:8080
  • Recv-Q == Send-Q → 危险

四、常见解决方案

✅ 1. 增大 backlog

listen(fd, 1024);

并调整:

sysctl -w net.core.somaxconn=4096

✅ 2. 增大 syn backlog

sysctl -w net.ipv4.tcp_max_syn_backlog=8192

✅ 3. 使用多线程 / 多进程 accept

  • SO_REUSEPORT
  • 线程池 accept

✅ 4. 快速 accept + 异步处理

  • accept 后立刻丢给线程
  • 不在 accept 线程里做业务

五、一句话总结

Linux backlog 丢包,本质是:连接已经完成或正在建立,但内核队列或应用消费跟不上。

如果你愿意,可以告诉我:

  • TCP 还是 UDP
  • 丢包发生在 连接建立还是收数据
  • 用的什么语言 / 框架(Nginx、Go、Java、C…)

我可以给你更针对性的排查方案。

0