【Linux内核-03】Linux下的TCP调优
linux下的tcp调优
TCP握手

流程
send syn
-
tcp_syn_retries:
net.ipv4.tcp_syn_retries = 6 //默认值为6次
重传syn的最大次数,重传失败连接超时。
半连接
-
tcp_max_syn_backlog:
net.ipv4.tcp_max_syn_backlog = 1024 //默认半连接队列1024
SYN半连接队列的最大长度
-
tcp_syncookies:
net.ipv4.tcp_syncookies = 1 //0: 不开启; 1: 半连接满开启; 2: 无条件开启
跳过半连接队列建立连接,有助于防御syn泛洪攻击
send syn+ack
-
tcp_synack_retries
net.ipv4.tcp_synack_retries = 5 //默认值为5次
重传syn+ack最大次数,重传失败会 丢弃连接 或 通知client(需开启tcp_abort_on_overflow)
导致重传的原因:(1)连接失败(2)accpet队列满
-
tcp_abort_on_overflow
net.ipv4.tcp_abort_on_overflow = 0 //0:丢弃;1:通知客户端
send ack
第三次握手超时未收到需要重传ack。
Syn队列 与 Accept队列
半连接队列
$ netstat -s | grep "SYNs to LISTEN" //判断半连接队列的溢出情况
如何增大半连接队列:
增大半连接队列(tcp_max_syn_backlog)+ 增大全连接队列(min(somaxconn, backlog))
溢出处理:
(1)重传syn,超过最大次数丢弃连接
(2)设置tcp_syncookies = 1
,跳过半连接进行连接
全连接队列
$ ss -lnt
RecvQ:当前全连接队列大小
SendQ:全连接队列最大长度
如何增大全连接队列:
全连接队列取决于:min(somaxconn, backlog)
somaxconn:Linux 内核的参数,默认值是 128
backlog:listen(int sockfd, int backlog) 函数中的 backlog 大小
溢出处理:
(1)重传syn+ack,超过最大次数丢弃连接
(2)设置tcp_abort_on_overflow = 0
,通知客户端断开
TCP传输
缓存机制
累计确认 + 快速重传
调整写缓冲区:
$ echo "4096 16384 4194304"> /proc/sys/net/ipv4/tcp_wmem
//第一个数值是动态范围的最小值,4096 byte = 4K;
//第二个数值是初始默认值,16384 byte ≈ 16K;
//第三个数值是动态范围的最大值,4194304 byte = 4096K(4M);
调整读缓冲区:
$ echo "4096 87380 291456"> /proc/sys/net/ipv4/tcp_rmem
//第一个数值是动态范围的最小值,表示即使在内存压力下也可以保证的最小接收缓冲区大小,4096 byte = 4K;
//第二个数值是初始默认值,87380 byte ≈ 86K;
//第三个数值是动态范围的最大值,6291456 byte = 6144K(6M);
窗口机制
发送窗口:swnd = min(cwnd, rwnd)
拥塞窗口:cwnd=(慢启动 + 拥塞避免)
接收窗口:rwnd=接收方缓存大小
tcp_window_scaling:启动窗口扩大因子
TCP挥手
流程

第一次、第二次挥手
-
tcp_orphan_retries
net.ipv4.tcp_synack_retries = 5 //默认值为5次
-
tcp_fin_timeout
net.ipv4.tcp_fin_timeout = 60
第三次、第四次挥手
TIME_WAIT 是主动方四次挥手的最后一个状态。
客户端每次收到FIN报文,重置时长为2MSL(Maximum Segment Lifetime)的计时器,超时自动close。
Time Wait
必要性
- 保证被动关闭方正常关闭
- 防止历史连接的数据被后续连接错误接收
优化
-
tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 18000 //系统中处于 TIME_WAIT 的连接一旦超过这个值时,系统就会将后面的 TIME_WAIT 连接状态重置
-
tcp_tw_reuse
net.ipv4.tcp_tw_reuse = 1 //客户端在调用connect()时,内核随机找一个 time_wait 状态超过 1 秒的连接给新的连接复用。
孤儿连接
close
tcp在两次挥手后进入孤儿连接的状态。
孤儿连接被读时,回复RST报错。
孤儿连接被写时,产生SIGPIPE信号。
shutdown
tcp在两次挥手后进入半连接的状态。
三次挥手
setsockopt(socketfd, IPPROTO_TCP, TCP_QUICKACK, (char*)& value, sizeof(int));
TCP_QUICKACK = 0时开启延迟确认。为提高效率,常常将回复的ACK携带在消息报文中,称为tcp的延迟确认机制。
端口占用问题
TCP和UDP可以绑定相同端口
服务端
- 多个tcp服务进程绑定相同 (ip, port) 时:Address already in use error。
- 重启服务进程时,存在Address already in use:上一次连接处于TIME_WAIT状态。
客户端
-
多个tcp客户进程使用相同的 (ip, port) 时:
显式调用bind:不可以绑定相同端口。
未显式调用bind:因为只要客户端连接的服务器不同,端口资源可以重复使用的(四元组决定).