相关阅读:
通过Linux Kernel参数探索TCP连接的建立
通过Linux Kernel参数探索TCP连接中的报文传输
//图片来自于网络
TCP连接的释放 T CP运用了可靠连接关闭,即经过双方的确认后再关闭连接,避免双方因不知道连接关闭造成业务问题。 跟握手不同,挥手可以由 客户端发起,也可以是服务端发起。发起关闭的一端我们称之为主动关闭方,另一端称之为被动关闭方。 客户端主动关闭 如果客户端主动关闭连接,那就是正常的关闭了。 首先客户端发起关闭连接的请求,服务端收到后,先发送ACK给客户端表示已收到关闭请求,然后客户端到服务端的连接就可以关闭了。 此时:服务端不会立刻关闭连接,它会将还没发完的数据发送到客户端。
客户端只是不能向服务端发送数据,但是可以接受数据,这就是TCP的半关闭。
客户端处于FIN_WAIT2,服务端处于CLOSE_WAIT状态。
如果服务端不关闭连接,将会一直处于CLOSE_WAIT状态,如果连接很多,这将会浪费大量的socket资源。 如果客户端一直没有接收到从服务端发出的FIN,也将一直处于FIN_WAIT2状态。Linux kernel通过参数net.ipv4.tcp_fin_timeout来控制这个状态的等待超时时间,默认值是60秒。等待时间超过这个值,客户端直接释放TCP连接。
服务端在发送完数据后再向客户端发起关闭连接的请求,客户端收到并返回确认后进入TIME_WAIT状态。它再经过时间等待计时器设置的2MSL后,TCP全双工连接就关闭了。
MSL(Maximum Segment Lifetime),即报文最大生存时间。
2MSL是TCP协议建议。在Linux kernel 4.1.12中,这个值固定为60s,如下图所示。
认为它是一个异常终止连接,客户端将会收到一个RST复位响应(而不是ACK响应);
如果客户端再次向服务端发送数据,系统将会发送一个SIGPIPE信号给客户端进程,告诉客户端进程该连接已关闭,不要再写了。
系统给SIGPIPE信号的默认处理是直接终止收到该信号的进程,所以此时客户端进程会被极不情愿地终止。
有价值的kernel参数
1 net.ipv4.TCP_tw_resue=1
处于TIME-WAIT状态的TCP连接,在链接表中存活1分钟。这意味着另一个相同四元组(源地址,源端口,目标地址,目标端口)的连接在这1分钟内不能出现,或者说新的TCP(相同四元组)连接无法建立。
启用net.ipv4.tcp_tw_reuse后,如果新的TCP连接的时间戳比以前存储的时间戳更大,那么linux将会从TIME-WAIT状态的存活连接中选取一个,重新分配给新的连接出去的TCP连接。2 net.ipv4.TCP_tw_recycle=1
此参数使能后,Linux kernel将TCP连接的TIME-WAIT状态,在超时重发(RTO)间隔后移除。
前面提到过,RTO_Base为200ms。所以在网络条件比较好的情况下,TIME_WAIT状态将会更早的过期。
在TIME_ WAIT过期之前,Linux将会放弃所有来自远程端的timestramp时间戳小于上次记录的时间戳的任何数据包。该参数在 Linux kernel4.12中已移除。
3 net.ipv4.ip_local_port_range
修改 net.ipv4.ip_local_port_range 选项中的可用端口范围,增加可同时存在的 TCP 连接数上限。
在Linux中作为客户端时,客户端端口默认可分配的数量不到30K个。这意味着:对于一个固定的服务,在客户端和服务端之间,每分钟只有30K个端口是处于established状态,大约500连接每秒。
如果这里的客户端是类似Nginx这样的负载均衡服务器的话,在不使用长连接的前提下,每秒500个连接在高并发场景下值有点小了。
4 net.ipv4.tcp_max_tw_buckets = 262144
表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,不会有新的 TIME_WAIT 产生。并打印警告信息。
如果没有新的TIME_WAIT产生,可能会出现下面几种异常:对端服务器发完最后一个 FIN 包,没有收到当前服务器返回最后一个 Ack,又重发了FIN 包,因为新的 TimeWait 没有办法创建 ,这个连接在当前服务器上就消失了,对端服务器将会收到一个 Reset 包。最后虽然TCP全双工连接都关闭了,但是对端服务器是通过异常流程关闭的连接,可能会对上层业务造成影响。
如果启用了TCP_tw_resue,当拥有相同五元组的连接出现并复用了当前TCP连接时,前一个连接的重复报文(如wandering duplicates,迷途报文)会在后一个连接上传输,会干扰上层应用的逻辑判断。
- End -