遇到一个奇怪的问题:当服务端处理不过来的时候,把客户端kill 掉,使用netstat 查看,还有established 状态的tcp 连接;
原因:由于服务器处理不过来,导致tcp 缓冲区堆积,FIN的数据包不是丢了就是还未被处理,netstat 信息如下:
tcp 129 0 0.0.0.0:15613 0.0.0.0:* LISTEN 37407/AAAAA
tcp 5346128 0 127.0.0.1:15613 127.0.0.1:56210 ESTABLISHED 37407/AAAAA
tcp 567364 0 127.0.0.1:15613 127.0.0.1:54450 ESTABLISHED 37407/AAAAA
tcp 5314874 0 127.0.0.1:15613 127.0.0.1:55764 ESTABLISHED 37407/AAAAA
在定位的过程中,纠正了自己之前的一个误解;
1,socket 默认是不打开keepalive 的,如果想打开需要执行:
int keepAlive = 1; // 非0值,开启keepalive属性
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行此TCP层的探测
int keepInterval = 5; // 探测发包间隔为5秒
int keepCount = 3; // 尝试探测的最多次数
setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount) ;
另外,tcp keepalive 的相关配置如下:
sudo sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
2,有数据时,重试的时间配置项:
root@localhost data0]# sysctl -a | grep tcp_retries
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15 // 15的单位是次数,大约960多秒
3,SS命令可以查看tcp 相关参数,例如,滑动窗口大小,timer 的类型等;
4,syn_queue 和 accept_queue 大小限制:
如果要设置未完成连接的队列长度,可以设置 tcp_max_syn_backlog
这个参数。
如果服务器收到大量的正常请求,导致服务器负载非常高,不要为了应对这种情况开启 tcp_syncookies
。
文档里用了大写的 “MUST NOT” 来提醒我们,然后很良心地建议去修改 tcp_max_syn_backlog
, tcp_synack_retries
, tcp_abort_on_overflow
。
系统发回给客户端 SYN/ACK 后,如果没收到客户端的 ACK,会重发 SYN/ACK,tcp_synack_retries
用于指定重发 SYN/ACK 的次数,默认是 5 次.
max syn queue size = 用户传入的 10 向上取了最接近的 2 的指数幂值 16。//backlog, net.core.somaxconn, net.ipv4.tcp_max_syn_backlog backlog 是listen 函数的参数
参考:https://juejin.cn/post/6844904071367753736
listen
函数的 backlog
等待应用程序 accept
的连接队列的长度,这个队列里是 ESTABLISHED
状态的连接,而不是还未完成三次握手的连接。
max accept queue: size = min(backlog, net.core.somaxconn)
注意,在4.3版本之前的内核,SYN队列的大小是用另一种方式计算。
SYN队列的最大大小以前是用net.ipv4.tcp_max_syn_backlog
来配置,但是现在已经不再使用了。
现在用net.core.somaxconn
来同时表示SYN队列和Accept队列的最大大小。
参考连接:
https://blog.csdn.net/lanyang123456/article/details/90578453
http://www.netkiller.cn/linux/system/network/network.check.html
https://fixatom.com/some-doubts-and-misunderstandings-of-tcp/