
1.TCP 三次握手的性能提升1.1.客户端优化SYN_SENT 状态的优化客户端作为主动发起连接方首先它将发送SYN包于是客户端的连接就会处于SYN_SENT状态。如果客户端长时间没有收到SYNACK报文则会重发SYN包重发的次数由tcp_syn_retries参数控制默认是5次。你可以根据网络的稳定性和目标服务器的繁忙程度修改SYN的重传次数调整客户端的三次握手时间上限。1.2.服务端优化如何查看由于 SYN 半连接队列已满而被丢弃连接的情况如何调整 SYN 半连接队列大小要想增大半连接队列不能只单纯增大tcp_max_syn_backlog的值还需一同增大somaxconn和backlog也就是增大accept队列。最后改变了如上这些参数后要重启服务因为SYN半连接队列和accept队列都是在listen()初始化的。SYN_RCV 状态的优化服务端收到客户端SYN后发送SYNACK若无法收到客户端ACK会引发重传。修改重发次数的方法是调整tcp_synack_retries参数。accept 队列已满只能丢弃连接吗tcp_abort_on_overflow共有两个值分别是0和1其分别表示0如果accept队列满了那么server扔掉client发过来的ack1如果accept队列满了server发送一个RST包给client表示废掉这个握手过程和这个连接通常情况下应当把tcp_abort_on_overflow设置为0因为这样更有利于应对突发流量。如何调整 accept 队列的长度呢accept队列的长度取决于somaxconn和backlog之间的最小值也就是min(somaxconn, backlog)。如何查看服务端进程 accept 队列的长度Recv-Q当前accept队列的大小也就是当前已完成三次握手并等待服务端accept()的TCP连接Send-Qaccept队列最大长度上面的输出结果说明监听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 4096K4M调节接收缓冲区范围第一个数值是动态范围的最小值表示即使在内存压力下也可以保证的最小接收缓冲区大小4096 byte 4K第二个数值是初始默认值87380 byte ≈ 86K第三个数值是动态范围的最大值6291456 byte 6144K6M发送缓冲区的调节功能是自动开启的而接收缓冲区则需要配置tcp_moderate_rcvbuf为1来开启调节功能。调节 TCP 内存范围上面三个数字单位不是字节而是「页面大小」1页表示4KB它们分别表示当TCP内存小于第1个值时不需要进行自动调节在第1和第2个值之间时内核开始调节接收缓冲区的大小大于第3个值时内核不再为TCP分配新内存此时新连接是无法建立的在socket上直接设置SO_SNDBUF或者SO_RCVBUF这样会关闭缓冲区的动态调整功能。