Linux 中 backlog 溢出 通常指的是 TCP 监听队列(listen backlog)溢出,常见于高并发服务(如 Nginx、Redis、MySQL、自研服务)。下面从 原理、原因、现象、排查与解决 几个层面说明。
在 Linux 网络编程中,socket 建立过程如下:
socket()bind()listen(int sockfd, int backlog)connect()accept() 取连接backlog 表示:
已完成三次握手、但还未被
accept()取走的 ESTABLISHED 连接队列长度上限
在 Linux 中,listen() 的 backlog 不是单一队列长度,而是:
实际队列长度 = min(backlog, net.core.somaxconn)
并且 Linux 内部有两个队列(历史实现略有差异):
| 队列 | 说明 |
|---|---|
| 半连接队列(SYN queue) | 收到 SYN,未完成握手 |
| 全连接队列(Accept queue) | 完成三次握手,等待 accept |
backlog 溢出通常指:全连接队列已满
listen(fd, 128);
而系统默认:
net.core.somaxconn = 128
高并发下瞬间被打满。
accept() 调用慢即使 backlog 很大,也会被迅速填满。
恶意大量 SYN,导致:
以下参数过小也会导致问题:
net.core.somaxconn
net.ipv4.tcp_max_syn_backlog
connection refusedconnection timeoutreset by peeraccept() 阻塞ss -lnt
示例:
Recv-Q Send-Q Local Address:Port
128 128 0.0.0.0:80
如果 Recv-Q == Send-Q,说明 队列已满
netstat -s | grep -i listen
或:
grep -i overflow /proc/net/snmp
看到类似:
ListenOverflows: 12345
ListenDrops: 12345
✅ 明确说明 backlog 溢出
tcpdump -i eth0 port 80
可能看到:
应用层:
listen(fd, 1024);
系统层:
sysctl -w net.core.somaxconn=1024
sysctl -w net.ipv4.tcp_max_syn_backlog=2048
写入配置文件:
/etc/sysctl.conf
epoll避免大量短连接冲击 backlog。
sysctl -w net.ipv4.tcp_syncookies=1
❌ backlog = 最大连接数
✅ 只是 已完成握手但未 accept 的队列
❌ 调大 backlog 就一定能抗并发
✅ 还取决于 accept() 速度和系统资源
❌ ESTABLISHED 很多就是 backlog 不够
✅ 要看 Recv-Q 是否等于 Send-Q
Linux backlog 溢出本质原因:已完成 TCP 三次握手的连接,来不及被应用 accept,导致队列被打满,新连接被丢弃。
如果你愿意,可以告诉我:
我可以给你一个 针对性的参数和架构优化方案。