TCP相关内核参数调优

2021年6月24日 5点热度 0条评论 来源: 清枫cc

TCP学习资料强烈推荐小林Coding,画的图是真心好,下面的大部分参数介绍都摘自通过小林Coding的 图解网络-TCP篇了解到:
https://wwr.lanzoui.com/iUqoUovm6wf

大佬CSDN:
https://blog.csdn.net/qq_34827674?spm=1001.2014.3001.5509

内核TCP参数优化

# TCP kernel paramater
net.ipv4.tcp_mem = 786432 1048576 1572864
net.ipv4.tcp_rmem = 4096        87380   4194304
net.ipv4.tcp_wmem = 4096        16384   4194304
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1

# socket buffer
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 20480
net.core.optmem_max = 81920

# TCP conn
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_max_tw_buckets = 20000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syncookies = 1

# tcp conn reuse
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_fin_timeout = 1

# keepalive conn
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 10001    65000

TCP状态切换

客户机端的三次握手和四次挥手状态转换

服务器端的三次握手和四次挥手状态转换

连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出了。此时客户端连接由内核来接管,可称之为孤儿连接(和孤儿进程类似)

1. Linux为了防止孤儿连接长时间存留在内核中,定义了三个内核参数:

/proc/sys/net/ipv4/tcp_max_orphans #指定内核能接管的孤儿连接数目 默认8192
/proc/sys/net/ipv4/tcp_fin_timeout #指定孤儿连接在内核中生存的时间 默认60s
/proc/sys/net/ipv4/tcp_orphan_retries = 0 #指定了FIN报文最多重发多少次,默认0,源码判断如果为0那就是特指8

2. TCP的TIME-WAIT连接状态相关参数

net.ipv4.tcp_max_tw_buckets #TIME-WAIT状态是很重要的,但是也消耗着系统资源,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT ⽽直接关闭: 
net.ipv4.tcp_tw_reuse # 1表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认值为0,表示关闭
net.ipv4.tcp_tw_recycle #不建议开启,会加速time_wait时间容易引起数据错乱,另外在nat,lvs环境会有大问题。在 Linux 4.12 版本后,Linux 内核直接取消了这⼀参数,建议关闭它

注意,要使用这一选项,需要开启时间戳的支持
net.ipv4.tcp_timestamps

2.1 TIME-WAIT状态的作用是什么?
  1. 防⽌收到历史数据(相同四元组(源IP,目的IP,源端口,目的端口)的旧数据包),从⽽导致数据错乱的问题
  2. 确保被动关闭方 能够正常关闭连接。即保证最后的 ACK 能让被动关闭⽅接收,从⽽帮助其正常关闭;
2.3 MSL是什么?

Max Segment Lifetime 一个报文在网络中的最大生存时间

2.4 2MSL时长是多少?

60s

2.5 为什么是2倍的MSL?

这其实是相当于⾄少允许报⽂丢失⼀次。⽐如,若 ACK 在⼀个 MSL 内丢失,这样被动⽅重发的 FIN 会在第 2 个 MSL 内到达,TIME_WAIT 状态的连接可以再次响应ACK

3. sync半连接和accept全连接队列

linuxkernel2.2版本之后增加

3.1 修改半连接队列的大小

tcp连接处于半开连接的都会放到syns queue队列中。
/proc/sys/net/ipv4/tcp_max_syn_backlog #未完成连接队列大小,默认值128,建议调整大小为1024以上

注意:半连接队列最大并不完全依赖于tcp_max_syn_backlog,还有可能依赖于全连接队列大小的值来决定,根据内核版本不同的定义可能不同。

3.1.2 如何查看 TCP 半连接队列⻓度?

ss -tln只能查看全连接队列,不能查看半连接队列,可以通过统计 SYN_RECV状态的连接
ss -tanp |grep SYN_RECV |wc -l

如何得知TCP半连接是否溢出了?
netstat -s | grep "SYNs to LISTEN" #每隔几秒查看一次,增加即是溢出了

3.1.3 TCP半开连接队列满了之后的策略
  1. 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
  2. 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
  3. 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列⻓度⼩于 (max_syn_backlog>> 2),则会丢弃

tcp_syncookies 默认开启1,值为1表示,当半连接队列满之后启用syncookies,服务器根据当前状态计算出⼀个值,放在⼰⽅发出的 SYN+ACK 报⽂中发出,当客户端返回 ACK 报⽂时,取出该值验证,如果合法,就认为连接建⽴成功

3.1.4 如何防御 SYN 攻击?

增⼤半连接队列;
开启 tcp_syncookies 功能
减少 SYN+ACK 重传次数

3.2 修改完全连接队列的大小

完全建立连接的会放到accept queue队列中。
TCP 全连接队列的最⼤值取决于 somaxconnbacklog 之间的最⼩值,也就是 min(somaxconn, backlog)
backloglisten(int sockfd, int backlog) 函数中的 backlog ⼤⼩,Nginx 默认值是511,可以通过修改配置⽂件设置其⻓度;
listen 8088 default backlog=5000
nignx -s reload 重新加载可以生效

/proc/sys/net/core/somaxconn #完成连接队列大小,默认值128,建议调整大小为1024以上

3.2.1 如何知道应⽤程序的 TCP 全连接队列⼤⼩?
#ss -tln 
「listen状态」的Recv-Q\Send-Q含义如下:
Recv-Q:当前全连接队列的⼤⼩,也就是当前已完成三次握⼿并等待服务端 accept() 的 TCP 连接;
Send-Q:当前全连接最⼤队列⻓度,上⾯的输出结果说明监听 8088 端⼝的 TCP 服务,最⼤全连接⻓度为128;
在「⾮ LISTEN 状态」时, Recv-Q/Send-Q 表示的含义如下
Recv-Q:已收到但未被应⽤进程读取的字节数;
Send-Q:已发送但未收到确认的字节数;
3.2.2 如何得知TCP全连接是否溢出了?

netstat -s|grep overflow #用来查看是否溢出了,没有返回则没有溢出。

3.2.3 TCP全连接满了之后会进行什么操作?

tcp_abort_on_overflow控制着当TCP全连接队列满了之后,使用什么策略来回复客户端。

  • 0 丢弃client发过来的ack,默认值
  • 1 直接回复reset报文断开连接,客户端可以看到connection reset by peer 的错误

通常设置为0,举个例子
当 TCP 全连接队列满导致服务器丢掉了 ACK,与此同时,客户端的连接状态却是 ESTABLISHED,进程就在建⽴好的连接上发送请求。只要服务器没有为请求回复 ACK,请求就会被多次重发。如果服务器上的进程只是短暂的繁忙造成 accept 队列满,那么当 TCP 全连接队列有空位时,再次接收到的请求报⽂由于含有 ACK,仍然会触发服务器端成功建⽴连接。

4.如何绕过三次握⼿?

linux内核3.7之后,提供了Fast Open选项字段实现快速功能
第一遍三次握手的时候,服务器会发给客户端一个cookie,下次再发起tcp连接时 可以将syc和cookie和请求的数据一起发给服务端,服务端校验通过之后可以直接返回数据,无需等待客户端的第三次握手ack.

4.1 Linux 下怎么打开 TCP Fast Open 功能呢?

tcp_fastopn 各个值的意义:

  • 0 关闭
  • 1 作为客户端使⽤ Fast Open 功能
  • 2 作为服务端使⽤ Fast Open 功能
  • 3 ⽆论作为客户端还是服务器,都可以使⽤ Fast Open 功能

TCP Fast Open 功能需要客户端和服务端同时⽀持,才有效果。

5.TCP 第⼀次握⼿ SYN 丢包会发生什么?

超时重传,重传6次,net.ipv4.tcp_syn_retries 这个参数控制着tcp syn第一次请求超时重传的次数。 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_syn_retries,默认值为6
每次RTO(超时重传)时间呈指数级增长,1,2,4,8,16,32

6. TCP第二次 握手SYN、ACK 丢包会发生什么?

客户端收不到服务端第二次的响应会重传tcp_syn_retries 次,每次重传会触发服务端响应syn、ack报文。
服务端发出syn、ack报文收不到客户端ack,也会超时重传。net.ipv4.tcp_synack_retries 参数的值决定了重传SYN+ACK包第二个请求的数量。 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_synack_retries,默认值为5

7.TCP第三次握手ack丢包会发生什么?

客户端发送syn到服务器,服务器响应syn、ack到客户端,此时客户端的状态时established,服务端状态是SYN_RECV的。
客户端响应给服务端的ack丢包之后,服务端会超时重传synack_retries次,超过次数服务端连接就会断开消失。
如果客户端一直没有发送数据包,那么客户端的状态会一直处于Established,当客户端开始发送数据包时,会得不到响应,则会一直超时重传/proc/sys/net/ipv4/tcp_retries2次,客户端才断开连接。

当重传次数超过tcp_retries1就会指示 IP 层进⾏ MTU 探测、刷新路由等过程,并不会断开TCP连接,
当重传次数超过tcp_retries2 才会断开TCP流。

7.1 如果客户端一直不发送数据,那么这个死链接会保持多久?

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9

当连接建立之后一直没有数据发送,等到7200s(2小时)之后才会启动保活机制,每隔75s发送一次探测报文,最多探测9次,也就是等待
7200+75*9 2个小时11分15秒linux才能发现一个死亡连接

8. TCP传输相关

net.ipv4.tcp_window_scaling 默认开启,支持扩展窗口
tcp的窗口字段才16个字节,意味着窗口大小最多支持2^16=65536个字节,也就是64k。这很明显是不够用的,通过额外使用tcp选项字段里的扩展窗口 2^14*2^16最大可以支持1G

8.1 缓冲区大小的调整

尽量将发送缓冲区的大小往带宽时延积靠近。
带宽时延积=RTT*带宽
⽐如最⼤带宽是 100 MB/s,⽹络时延(RTT)是 10ms 时,意味着客户端到服务端的⽹络⼀共可以存放 100MB/s* 0.01s = 1MB 的字节

  • 发送缓冲区超出带宽时延积有可能造成网络拥塞
  • 小于带宽时延积则达不到最高的网络利用率。

net.ipv4.tcp_wmem 根据设定的范围动态调节TCP发送缓冲区

  • 第⼀个数值是动态范围的最⼩值,4096 byte = 4K;
  • 第⼆个数值是初始默认值,87380 byte ≈ 86K;
  • 第三个数值是动态范围的最⼤值,4194304 byte = 4096K(4M);

net.ipv4.tcp_rmem根据设定的范围动态调节TCP接受缓冲区

  • 第⼀个数值是动态范围的最⼩值,表示即使在内存压⼒下也可以保证的最⼩接收缓冲区⼤⼩,4096 byte =4K;
  • 第⼆个数值是初始默认值,87380 byte ≈ 86K;
  • 第三个数值是动态范围的最⼤值,6291456 byte = 6144K(6M);

tcp_moderate_rcvbuf发送缓冲区的自动调节功能是开启的,而接受缓冲区的自动调节功能是根据tcp_moderate_rcvbuf 值来开启的,1表示开启。

8.2 什么时候动态调整接收缓冲区呢?

这是通过 tcp_mem 配置完成的:
net.ipv4.tcp_mem = 22161 29548 44322
上⾯三个数字单位不是字节,⽽是「⻚⾯⼤⼩」,1 ⻚表示 4KB,它们分别表示:

  • 当 TCP 内存⼩于第 1 个值时,不需要进⾏⾃动调节;
  • 在第 1 和第 2 个值之间时,内核开始调节接收缓冲区的⼤⼩;
  • ⼤于第 3 个值时,内核不再为 TCP 分配新内存,此时新连接是⽆法建⽴的;
    原文作者:清枫cc
    原文地址: https://blog.csdn.net/ledrsnet/article/details/118189975
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。