这是一个非常经典且重要的问题,尤其在网络编程和系统性能调优中。简单来说,backlog 是连接队列大小的上限,它直接决定了系统能同时容纳多少个正在建立(半连接)或已建立(全连接)但尚未被应用程序处理的连接。
下面我们分层次详细解释:
在TCP/IP协议中,当服务端调用 listen() 系统调用后,内核会维护两个队列来管理与客户端的连接过程:
半连接队列(SYN Queue):
SYN 包,服务端收到后回复 SYN+ACK,此时连接处于 SYN_RCVD 状态。这个连接就被放入半连接队列。net.ipv4.tcp_max_syn_backlog 参数影响。但在现代内核中,它也和 backlog 参数以及 somaxconn 有关,是一个复杂计算的结果。全连接队列(Accept Queue):
ACK),连接处于 ESTABLISHED 状态,但尚未被服务器应用程序调用 accept() 取走。这个连接就被放入全连接队列。backlog 参数直接影响的队列! 它的实际最大值取 min(backlog, net.core.somaxconn)。somaxconn 是系统级内核参数,默认值通常是128或512。在编程中(如 socket.listen(backlog)),你设置的 backlog 参数,传统上和本质上,指的是全连接队列的最大长度。
accept() 不够快,请至少帮我缓存 backlog 个已经建立好的连接。”backlog 和系统限制(somaxconn),计算出全连接队列的实际大小。一个非常重要的现代Linux行为: 在Linux 2.2以后,backlog 参数的行为发生了变化。它现在表示已完成连接队列(全连接队列)的最大长度,而半连接队列的长度由系统参数 tcp_max_syn_backlog 和 somaxconn 等共同控制,但 backlog 也会间接影响它。
我们来看看一个连接从生到死的过程,以及它如何与队列和 backlog 交互:
SYN -> 服务端收到,将其放入半连接队列(如果队列未满)。SYN+ACK。ACK -> 服务端收到,连接完成三次握手。此时,内核会尝试将连接从半连接队列移到全连接队列。
min(backlog, somaxconn)),则移入成功。net.ipv4.tcp_abort_on_overflow 的行为:
ACK。这会导致客户端认为连接已建立,但服务端不认。客户端发送数据时,服务端会回复 RST 重置连接。或者,服务端可能会重发 SYN+ACK 给客户端(取决于实现),试图让客户端重新确认。RST 给客户端,明确告知连接被拒绝。accept() -> 从全连接队列头部取走一个连接,队列空间腾出。所以,关系可以总结为:
socket.listen())默认 backlog=5 或 128,这对于高并发服务(如Web服务器、API网关)通常太小。backlog 设置得大一些,例如 1024, 2048 或更高。# 查看当前全连接队列系统上限
cat /proc/sys/net/core/somaxconn
# 通常建议设置为 1024, 2048 或 4096
echo "net.core.somaxconn = 4096" >> /etc/sysctl.conf
# 查看半连接队列相关参数
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
# 也建议调大
echo "net.ipv4.tcp_max_syn_backlog = 8192" >> /etc/sysctl.conf
# 使配置生效
sysctl -p
listen(backlog) 的 backlog 值设置为与 somaxconn 相同或更大(因为内核会取两者最小值,设大一点无妨,但设小了会被系统限制)。# 查看因全连接队列满而被丢弃的连接数(Linux)
netstat -s | grep -i "listen queue"
# 或者更精确的(需要较新内核和iproute2)
ss -lnt
# 看 Send-Q 和 Recv-Q。对于监听套接字,Send-Q 表示当前全连接队列长度,Recv-Q 表示配置的全连接队列最大长度(即 backlog 和 somaxconn 的最小值)。
# 如果 Send-Q 经常接近 Recv-Q,说明队列快满了。
| 项目 | 半连接队列 (SYN Queue) | 全连接队列 (Accept Queue) |
|---|---|---|
| 存储的连接状态 | SYN_RCVD (正在握手) |
ESTABLISHED (已建立,等应用accept) |
| 主要控制参数 | net.ipv4.tcp_max_syn_backlog (及 somaxconn, backlog) |
backlog 参数 和 net.core.somaxconn |
| backlog 的直接影响 | 间接影响(通过影响全队列和算法) | 直接影响 |
| 队列满的后果 | 丢弃新的 SYN 包,客户端可能超时 |
丢弃 ACK 或回复 RST,连接建立失败 |
| 应用程序如何消费 | 内核自动处理(完成握手后移入全队列) | 调用 accept() 从队列中取走 |
一句话概括:backlog 主要定义了你的服务端程序在调用 accept() 之前,内核允许为你缓存多少个已经完全建立好的TCP连接。它是连接管理中承上启下的关键缓冲参数。