理解网络--Tcp性能优化

1.TCP 三次握手的性能提升

1.1.客户端优化

SYN_SENT 状态的优化

客户端作为主动发起连接方,首先它将发送 SYN 包,于是客户端的连接就会处于 SYN_SENT 状态。

如果客户端长时间没有收到 SYN+ACK 报文,则会重发 SYN 包,重发的次数由 tcp_syn_retries 参数控制,默认是 5 次。

你可以根据网络的稳定性和目标服务器的繁忙程度修改 SYN 的重传次数,调整客户端的三次握手时间上限。

1.2.服务端优化

如何查看由于 SYN 半连接队列已满,而被丢弃连接的情况?

如何调整 SYN 半连接队列大小?

要想增大半连接队列,不能只单纯增大 tcp_max_syn_backlog 的值,还需一同增大 somaxconn 和 backlog,也就是增大 accept 队列。

最后,改变了如上这些参数后,要重启服务,因为 SYN 半连接队列和 accept 队列都是在 listen() 初始化的。

SYN_RCV 状态的优化

服务端收到客户端SYN后,发送SYN+ACK,若无法收到客户端ACK,会引发重传。修改重发次数的方法是,调整 tcp_synack_retries 参数。

accept 队列已满,只能丢弃连接吗?

tcp_abort_on_overflow 共有两个值分别是 0 和 1,其分别表示:

  • 0 :如果 accept 队列满了,那么 server 扔掉 client 发过来的 ack ;
  • 1 :如果 accept 队列满了,server 发送一个 RST 包给 client,表示废掉这个握手过程和这个连接;

通常情况下,应当把 tcp_abort_on_overflow 设置为 0,因为这样更有利于应对突发流量。

如何调整 accept 队列的长度呢?

accept 队列的长度取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)。

如何查看服务端进程 accept 队列的长度?

  • Recv-Q:当前 accept 队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接;
  • Send-Q:accept 队列最大长度,上面的输出结果说明监听 8088 端口的 TCP 服务,accept 队列的最大长度为 128;

如何查看由于 accept 连接队列已满,而被丢弃的连接?

上面看到的 41150 times ,表示 accept 队列溢出的次数。

如果持续不断地有连接因为 accept 队列溢出被丢弃,就应该调大 backlog 以及 somaxconn 参数。

1.3.如何绕过三次握手?

在 Linux 3.7 内核版本之后,提供了 TCP Fast Open 功能,这个功能可以减少 TCP 连接建立的时延。

接下来说说,TCP Fast Open 功能的工作方式

开启了 TFO 功能,cookie 的值是存放到 TCP option 字段里的:

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

在 Linux 系统中,可以通过设置 tcp_fastopn 内核参数,来打开 Fast Open 功能:

tcp_fastopn 各个值的意义:

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

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

2.TCP 四次挥手的性能提升

2.1.主动方的优化

调用 close 函数

调用了 close 函数意味着完全断开连接,完全断开不仅指无法传输数据,而且也不能发送数据。 此时,调用了 close 函数的一方的连接叫做「孤儿连接」,如果你用 netstat -p 命令,会发现连接对应的进程名为空。

调用shutdown

第二个参数决定断开连接的方式,主要有以下三种方式:

  • SHUT_RD(0):关闭连接的「读」这个方向,如果接收缓冲区有已接收的数据,则将会被丢弃,并且后续再收到新的数据,会对数据进行 ACK,然后悄悄地丢弃。
  • SHUT_WR(1):关闭连接的「写」这个方向,这就是常被称为「半关闭」的连接。如果发送缓冲区还有未发送的数据,将被立即发送出去,并发送一个 FIN 报文给对端。
  • SHUT_RDWR(2):相当于 SHUT_RD 和 SHUT_WR 操作各一次,关闭套接字的读和写两个方向。

FIN_WAIT1 状态的优化

当迟迟收不到对方返回的 ACK 时,连接就会一直处于 FIN_WAIT1 状态。此时,内核会定时重发 FIN 报文,其中重发次数由 tcp_orphan_retries 参数控制。

控制孤儿连接数量

当进程调用了 close 函数关闭连接,此时连接就会是「孤儿连接」,因为它无法再发送和接收数据。 控制参数 tcp_max_orphans 。如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST 复位报文强制关闭。

FIN_WAIT2 状态的优化

如果连接是用 shutdown 函数关闭的,连接可以一直处于 FIN_WAIT2 状态。但对于 close 函数关闭的孤儿连接,由于无法再发送和接收数据,所以这个状态不可以持续太久,而 tcp_fin_timeout 控制了这个状态下连接的持续时长,默认值是 60 秒。它意味着对于孤儿连接(调用 close 关闭的连接),如果在 60 秒后还没有收到 FIN 报文,连接就会直接关闭。

TIME_WAIT 状态的优化

  • Linux 提供了 tcp_max_tw_buckets 参数,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。
  • 有一种方式可以在建立新连接时,复用处于 TIME_WAIT 状态的连接,那就是打开 tcp_tw_reuse 参数。但是需要注意,该参数是只用于客户端(建立连接的发起方),因为是在调用 connect() 时起作用的。tcp_tw_reuse 从协议角度理解是安全可控的,可以复用处于 TIME_WAIT 的端口为新的连接所用。复用条件:
    • 只适用于连接发起方,也就是 C/S 模型中的客户端;
    • 对应的 TIME_WAIT 状态的连接创建时间超过 1 秒才可以被复用。
    • 需要打开对 TCP 时间戳(tcp_timestamps)的支持(对方也要打开 ),引入时间戳下历史报文可被识别并丢弃,序列号回绕也可正确识别。
  • 可以在程序中设置 socket 选项,来设置调用 close 关闭连接行为。

    如果 l_onoff 为非 0, 且 l_linger 值为 0,那么调用 close 后,会立该发送一个 RST 标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了 TIME_WAIT 状态,直接关闭。

2.2.被动方的优化

被动方执行close发出FIN后,无法及时收到ACK,引发重传。重传控制参数:tcp_orphan_retries。

如果连接双方同时关闭连接,会怎么样?

3.TCP 传输数据的性能提升

窗口尺寸

这个窗口大小最大值,在当今高速网络下,很明显是不够用的。所以后续有了扩充窗口的方法:在 TCP 选项字段定义了窗口扩大因子,用于扩大 TCP 通告窗口,在 TCP 选项字段定义了窗口扩大因子,用于扩大 TCP 通告窗口,所以此时窗口的最大值可以达到 1GB。

Linux 中打开这一功能,需要把 tcp_window_scaling 配置设为 1(默认打开)。

要使用窗口扩大选项,通讯双方必须在各自的 SYN 报文中发送这个选项:

  • 主动建立连接的一方在 SYN 报文中发送这个选项;
  • 而被动建立连接的一方只有在收到带窗口扩大选项的 SYN 报文之后才能发送这个选项。

如何确定最大传输速度?

比如最大带宽是 100 MB/s,网络时延(RTT)是 10ms 时,意味着客户端到服务端的网络一共可以存放 100MB/s * 0.01s = 1MB 的字节。

由于发送缓冲区大小决定了发送窗口的上限,而发送窗口又决定了「已发送未确认」的飞行报文的上限。因此,发送缓冲区不能超过「带宽时延积」。

发送缓冲区与带宽时延积的关系:

  • 如果发送缓冲区「超过」带宽时延积,超出的部分就没办法有效的网络传输,同时导致网络过载,容易丢包;
  • 如果发送缓冲区「小于」带宽时延积,就不能很好的发挥出网络的传输效率。

所以,发送缓冲区的大小最好是往带宽时延积靠近。

调节发送缓冲区范围

  • 第一个数值是动态范围的最小值,4096 byte = 4K;
  • 第二个数值是初始默认值,16384 byte ≈ 16K;
  • 第三个数值是动态范围的最大值,4194304 byte = 4096K(4M);

调节接收缓冲区范围

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

发送缓冲区的调节功能是自动开启的,而接收缓冲区则需要配置 tcp_moderate_rcvbuf 为 1 来开启调节功能。

调节 TCP 内存范围

上面三个数字单位不是字节,而是「页面大小」,1 页表示 4KB,它们分别表示:

  • 当 TCP 内存小于第 1 个值时,不需要进行自动调节;
  • 在第 1 和第 2 个值之间时,内核开始调节接收缓冲区的大小;
  • 大于第 3 个值时,内核不再为 TCP 分配新内存,此时新连接是无法建立的;

在 socket 上直接设置 SO_SNDBUF 或者 SO_RCVBUF,这样会关闭缓冲区的动态调整功能。

控制连接状态下重发

tcp_retries2控制在 TCP 连接建立的情况下,超时重传的最大次数。内核会根据 tcp_retries2 设置的值,计算出一个timeout,如果重传耗时达到此timeout,即使尚未达到最大重传次数,也会立即断开连接。

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
wuyk5554 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
liangshanbo12154 天前
React 性能优化实战
性能优化·react
QYRdata4 天前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK4 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
mmsx4 天前
Android GIS系列 内存加锁、SQLite 开事务:矢量数据集双层并发设计
android·性能优化·app
chshang19924 天前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
萧瑟余晖4 天前
Netty 核心组件与 Reactor 模型详解
网络·架构
ITxiaobing20234 天前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络