看得见的TCP
TCP三次握手和四次挥手
服务端将ACK和FIN合并一起发送,变成了“三次挥手”。
通常情况下,服务端收到客户端的FIN时,很可能还没发送完数据; 所以就会先回复客户端ACK。
TCP三次握手异常情况
TCP第一次握手的SYN丢包
超时时间RTO翻倍;当超过最大重传次数(tcp-syn-retries)后,客户端不再发送SYN包。
TCP第二次握手的SYN、ACK丢包
客户端会重传SYN包; 服务端会重传SYN-ACK包; 服务端收到客户端重传的SYN包后,超时定时器重新计时。
SYN-ACK最大重传次数:tcp-synack-retries
TCP第三次握手的ACK丢包
- 服务端重传SYN-ACK包超过了最大重传次数,断开连接;
- 客户端向服务端发送数据包,超时重传15次后,断开连接。
TCP建立连接后的数据包最大超时重传次数:tcp-retries
若客户端不发送数据,什么时候会断开处于ESTABLISHED状态的连接?
TCP的保活机制。
发现死亡连接时间=保活时间+检验间隔X检验次数
TCP快速建立连接
TCP重复确认和快速重传
TCP流量控制
发送窗口=min(拥塞窗口,接收窗口)
发送窗口决定了一口气能发多少字节,MSS决定了这些字节要分多少包发完。
TCP延迟确认与Nagle算法
Nagle算法
Nagle算法最开始时一定会有一个小报文。
延迟确认
当延迟确认和Nale算法混合使用时,会产生新问题
两个同时使用会造成额外的时延。
TCP半连接队列和全连接队列
丢弃连接请求:
- 若半连接队列满了,并且没有开启tcp-syncookies,则会丢弃;
- 如全连接队列满了,且没有重传SYN+ACK包的连接请求多于1个,则会丢弃;
- 若没有开启tcp-syncookies,并且 max_syn_backlog 减去 当前半连接队列⻓度⼩于(max_syn_backlog >> 2),则会丢弃;
若SYN半连接队列已满,只能丢弃连接吗?
开启syncookies。
服务端根据当前状态计算出一个值,放在SYN+ACK中发出; 当客户端返回ACK报文时,取出该值验证; 若合法,就认为连接建立成功。
如何防御SYN攻击?
- 增大半连接队列
- 开启tcp-syncookies 功能
- 减少SYN+ACK重传次数
当服务端收到SYN攻击时,就会有大量处于SYN-REVC状态的TCP连接; 处于这个状态的TCP会重传SYN+ACK,当重传次数达到上限后,就会断开连接。
我们可以减少SYN-ACK重传次数,加快TCP连接断开。
TCP内核参数
TCP三次握手的性能提升
客户端的优化
调整SYN报文的重传次数
服务端的优化
1. 调整SYN半连接队列长度
若半连接队列已满,只能丢弃连接吗?
2. 开启syncookies功能
3. 调整SYN—ACK报文的重传次数
4. 调整全连接队列长度
若全连接队列已满,只能丢弃连接吗?
我们还可以选择向客户端发送RST。 但是,应对突发流量时,直接扔掉客户端发来的ACK仍是更好的选择。
绕过三次握手
开启Fast Open功能
TCP四次挥手的性能提升
主动方的优化
主动方:主动发起FIN断开连接的一方。
主动发送FIN报文后,连接就处于FIN-WAIT1状态。 如果没有收到对方的ACK回复,则会重传FIN;可以调整FIN报文重传次数;
当进程调用了close函数关闭连接,那么它就是孤儿连接。 可以调整孤儿连接的上限个数。
当孤儿连接数量大于上限,新增的孤儿连接将不再走4次挥手,而是直接发送RST强制关闭。
若收到ACK报文,连接就进入FIN—WAIT2状态;
- 若这是close函数关闭的连接,可以:1. 调整FIN-WAIT2状态的时间;(若还没有收到FIN,连接会直接关闭)
- 反之,是shutdown函数关闭的连接,不受此参数限制。
当主动方接收到FIN,并返回ACK,主动方的连接就进入TIME-WAIT;可以:
1. 调整time-wait状态的上限个数; 超过上限处于time-wait状态的连接会被直接关闭。
2. 复用time-wait状态的连接(只适用客户端);
- 四次挥手中的最后一次ACK在网络中丢失,服务端处于LAST-ACK状态;
- 客户端由于开启了tcp-tw-reuse,再次连接时,会复用超过1s的time-wait的连接。但客户端新发的SYN会被忽略(由于时间戳),因为服务端比较了客户端的上一个报文与SYN的时间戳,过期的报文被服务端丢弃。
- 服务端FIN迟迟没有收到ACK,于是超时重发FIN;
- 处于SYN-SENT的客户端,由于收到FIN,则会回RST给服务端,于是服务端离开了LAST-ACK状态;
- 客户端SYN超时重发,与服务端重新三次握手。
被动方的优化
被动方内核在自动回复ACK后就进入CLOSE-WAIT,等待进程调用close关闭连接。因此,若出现大量CLOSE-WAIT,应从应用程序中找问题。
当被动方发送FIN报文后,连接就进入LAST-ACK状态,可以调整FIN重传次数。
如果连接双方同时关闭连接?
两方发送FIN报文时,都认为自己是主动方。
TCP数据传输的性能提升
TCP连接由内核维护,内核为每个连接建立内核缓冲区:
- 若内存配置过小,则无法充分利用带宽;
- 若内存配置过大,容易把服务器资源耗尽。
扩大窗口大小
在TCP选项字段定义了窗口扩大因子; 要使用窗口扩大选项,主动方和被动方必须在各自的SYN中发送该选项;
调整缓冲区
缓冲区要与网络传输能力匹配。
如何计算网络传输能力?带宽时延积。
发送缓冲区与带宽时延积的关系:
- 若发送缓冲区超过带宽时延积,超出的部分无法有效传输,导致网络过载,容易丢包。
- 若小于,则不能很好地发挥传输效率。
调节发送缓冲区范围
发送缓冲区是自行调节的; 当发送方数据被确认且没有新数据要发送时,就会释放缓冲区内存。
调节接收缓冲区范围
根据当前内存而定。
调节TCP内存范围