2024年6月

linux

三次握手

1.jpg

Client调用connect(),向server发送syn,如果出现丢包现象,client会重传syn,具体重传次数由tcp_syn_retries决定。同理还有控制syn+ack包重传次数的tcp_synack_retries

cat /proc/sys/net/ipv4/tcp_syn_retries
6

cat /proc/sys/net/ipv4/tcp_synack_retries
5

要注意的是,每一次重传所等待的时间都是上一次的两倍,tcp_syn_retries默认值为6,假设第一次等待1s,这代表要等待1+2+4+8+16+32+64=127秒后才会Timeout,这会导致大量的堵塞,建议调小

服务器收到SYN但还没回复SYN+ACK时,会去创建一个半连接,放在syn queue中,如果服务器的半连接数已经达到上限,新的半连接会被丢弃,所以服务器不回应也可能和此有关,可以适当调大
半连接上限控制的参数为

cat /proc/sys/net/ipv4/tcp_max_syn_backlog
4096

同理还有全连接上限的控制

cat /proc/sys/net/core/somaxconn
4096

半连接积压过多,也可能和遭受SYN Flood攻击导致,可以开启SYN Cookie机制,在收到SYN的时候不分配资源,根据SYN包计算出一个Cookie随着SYN+ACK一起返回回去,等收到ACK包而且Cookie没问题才分配资源创建链接
net.ipv4.tcp_syncookies = 1

全连接满了后,linux会丢弃新建的全连接,丢弃可以选择是否要通知对方reset,默认是不通知,也建议不通知,这样可以让对方进行重试

cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0

使用这条指令可以看当前所有连接统计数据
netstat -an | awk '/^tcp/ {++s[$NF]} END {for(a in s) print a, s[a]}'
查看半连接、全连接数、当前的全连接队列

netstat -natp | grep SYN_RECV | wc -l
netstat -natp | grep ESTABLISHED | wc -l
ss -lnt |grep port

3.png

四次挥手

2.png
一方发起FIN包,另一方收到后,如果数据已经处理完了,会回复ACK+FIN包,如果没处理完,会先ACK,等完成了再FIN,这时发起方回复ACK,自己断开。而在收到对方ACK但还没收到FIN包这期间,也就是FIN_WAIT_2,如果过长时间没收到对方的消息也会自动断开,这个时间也由参数控制,默认60s,可以改短避免浪费资源

cat /proc/sys/net/ipv4/tcp_fin_timeout
60

同理还有Time_wait,默认也为60s,这个要通过sysctl去修改

sudo vim /etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 5

sudo sysctl -p

https://andyx.net/modifying_linux_kernel_parameters_to_reduce_time-wait_connection/

处于time_wait状态的连接可以被复用,这样就不用浪费资源再开一个连接了,也在一定程度上解决端口有限问题,对客户端一方有效。注意还有个recycle的参数,那个不建议开,会引起NAT丢包

cat /proc/sys/net/ipv4/tcp_tw_reuse
2

+ 0 - disable
+ 1 - global enable
+ 2 - enable for loopback traffic only

容器网络ns

容器使用Network namespace来进行网络资源的隔离,具体隔离的有以下几种资源:

  1. 网络设备,如lo,eth0,可通过ip link查看
  2. TCP和UDP的协议栈
  3. 路由表,可用ip route查看
  4. 防火墙规则,iptables
  5. 网络状态信息,一般在/proc/net和/sys/class/net

使用lsns -t net可以查看当前设备上的网络ns,使用nsenter进入
因为ns的缘故,直接去修改宿主机的部分内核参数,是无法在容器里起作用的。而容器中这些参数是只读的,无法修改,如果要修改必须通过docker或者k8s来去修改runC的接口,docker是docker –sysctl,k8s是allowed-unsafe-sysctls

docker run -d --name net_para --sysctl net.ipv4.tcp_keepalive_time=600 centos:8.1.1911 sleep 3600
7efed88a44d64400ff5a6d38fdcc73f2a74a7bdc3dbc7161060f2f7d0be170d1
docker exec net_para cat /proc/sys/net/ipv4/tcp_keepalive_time
600