tcp协议之backlog

基本概念

20190716156324798318236.png

如图,syn_recd后会将请求放入syn_queue(半连接队列)中,而在established后会从syn_queue取出放入accept_queue(连接队列)中。

值得注意的是: backlog不等于最大连接数,backlog指的是还没有被accept取出的连接队列长度,可以理解为是一个暂存的缓冲区

详细说明

listen时可以传入backlog参数,真实生效的值等于min(/proc/sys/net/core/somaxconn,listen的backlog)

1
2
/proc/sys/net/ipv4/tcp_max_syn_backlog 半连接队列长度
/proc/sys/net/core/somaxconn 连接队列长度 min(somaxconn,backlog)
1
2
//临时修改
sysctl -w net.core.somaxconn=2048

可以使用ss -ntlp查看backlog,其中Recv-Q是当前连接队列长度,Send-Q是连接队列最大长度。其中Recv-Q大多数情况下应该是0,如果这个值比较大,就说明accept消费速率太低了 或者syn连接速率太高

1
2
3
4
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN0 100 127.0.0.1:9000 0.0.0.0:* users:(("php-fpm",pid=11554,fd=6),("php-fpm",pid=11106,fd=6),("php-fpm",pid=11040,fd=6),("php-fpm",pid=10522,fd=8))
LISTEN0 128 0.0.0.0:6699 0.0.0.0:* users:(("nginx",pid=12140,fd=9),("nginx",pid=3632,fd=9))
LISTEN0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=12140,fd=6),("nginx",pid=3632,fd=6))

FAQ

1.backlog引发的问题

backlog配置过大,accept处理不过来,导致连接队列堆积过多,那么有可能在accept之前客户端就已经超时,accept后再读取或写入会报错brokenpipe
backlog配置过小,导致连接队列一直处于满的情况,导致客户端握手失败无法连接,通常情况下服务端会直接忽略此次syn包(而不是返回RST包),以便客户端重试(而不是异常退出)
ps: accept队列满时,server通过/proc/sys/net/ipv4/tcp_abort_on_overflow决定如何响应,0表示直接丢弃,1表示响应RST,相应的client会收到read timeout或connection reset by peer。

通过netstat -s|grep drop可以看到SYNs to LISTEN sockets dropped

1
2
3
13 ICMP packets dropped because they were out-of-window
1 ICMP packets dropped because socket was locked
4539 SYNs to LISTEN sockets dropped

[译文]深入理解Linux TCP backlog
浅谈tcp socket的backlog参数
TCP/IP中的“积压值”和“最大连接数”是什么关系
TCP SOCKET中backlog参数的用途是什么?