Linux下TIME_WAIT连接优化内核参数tcp_tw_reuse与tcp_tw_recycle区别与联系浅析

概述

最近学习网络相关知识点,很多文章提到针对TCP time wait(后续简称TW)状态连接进行优化的参数tcp_tw_reuse和tcp_tw_recycle,并且不少文章提到了启用tcp_tw_recycle会导致的问题,不建议开启该选项,但是并没有找到一篇能完全解答自己所有疑惑的文章,如:

  1. Linux会丢弃所有来自远端的timestramp时间戳小于上次记录的时间戳(由同一个远端发送的)的任何数据包。也就是说要使用该选项,则必须保证数据包的时间戳是单调递增的,这里的远端定义的是ip还是ip+port? 是一定时间内丢弃时间戳过期packet还是tcp_tw_recycle启用后一直丢弃?
  2. 很多文章都会提到tcp_tw_reuse 仅作用于客户端连接,tcp_tw_recycle则同时作用于客户端与服务端连接,这里客户端、服务端连接具体指的是什么?与TCP三次握手的客户端、服务端概念上有什么区别?

通过学习网上大家的总结+阅读了部分4.9内核源码,这里整理总结一下从各处学习到的知识点及自己的理解。

过多time wait会导致的问题

  1. 客户端主动发起的连接总数受 max open file数限制,过多连接导致达到max open file限制将无法创建新的连接。
  2. 客户端主动发起的连接总数也受可用端口号限制,一般使用端口号为1024~65000,如果过多TW连接将端口号耗尽同样无法再创建新的连接。
  3. 每个TW连接都会占用一定的系统资源-如内存--实际耗费内存很小,这点一般可忽略

tcp_tw_reuse与tcp_tw_recycle相同点

  1. 两者目的均是为了解决系统中过多TW状态 TCP连接的问题。
  2. 两者都需要和tcp_timestamps 同时开启方能生效。
  3. 根据RFC定义,主动关闭连接方其TW状态需维持2MSL时间才正式关闭连接,Linux上MSL默认定义为30s,即TW状态默认需要维持1分钟方能正式关闭,tcp_tw_reuse与tcp_tw_recycle均为通过缩短TW状态时间进行复用来进行优化。
  4. 两个参数默认均为关闭状态

tcp_tw_reuse作用

  1. 仅作用于客户端方主动发起连接,即出向连接。
  2. 连接进入TW状态>1s,且新连接的timestamp大于旧连接记录的timestamp时方能复用连接。
  3. client提前中止TW状态进行复用,发起新连接,server依然处于last ack状态时,交互流程如下:
    1. client发送新SYN => server
    2. client <= server由于处于LAST ACK,不理会SYN,重发 FIN+ACK
    3. client收到FIN+ACK,发现timestamp已过期,发送RST => server, server收到后重置关闭旧连接
    4. client初始发送的SYN包等待ACK超时1s后,重发SYN => server
    5. client <= server 会发 SYN+ACK 进入正常三次握手连接过程...
    6. 新连接建立完成后,client/server若收到旧连接的历史报文,通过timestamp可判断出为旧报文直接丢弃
      整个过程中可以看到,client端可以正常复用发起新的连接,在server端依然处于LAST ACK状态时也只是需要稍微延迟一小段时间而已。

tcp_tw_recycle作用

  1. 同时作用于client/server发起连接,即出、入向连接
  2. TW状态维持3.5RTO(the retransmission timeout (RTO) interval which is computed from the RTT and its variance)之后就直接可以被过期回收,具体RTO取值是基于网络RTT及其他相关因子综合计算,一般在200ms~120s之间。
  3. TW状态后2MSL会丢弃所有来自远端相同四元组的timestamp小于上次记录timestamp的任何数据包,因而需要保证数据包timestamp是单调递增的
    1. NAT情况下,不同client从同一NAT ip请求,由于NAT不会更改包中的timestamp,而不同机器的时间不可能完全同步,因而不同机器从同一个NAT IP+port发出的包会存在timestamp非单调递增的情况,问题场景举例:
      1. 机器A时间比机器B快1s,机器A先通过NAT机器 ip1:port1 对服务器S ip2: port2 发起tcp连接socket1--使用conn_old(ip1, port1, ip2, port2)四元组表示
      2. 后S主动断开连接进入TW状态,由于开启tcp_tw_recycle,经过3.5RTO后S即可复用conn_old这个连接
      3. NAT机器对应连接在进入LAST ACK并收到S回复的ACK之后关闭了conn_old
      4. 而后机器B通过NAT机器发起conn_new(ip1, port1, ip2, port2)
      5. 此时S收到SYN包发现timestamp 小于conn_old中记录的最终timestamp,于是丢弃conn_new的SYN包
      6. 机器B超时未收到回复,重发SYN包,机器S收到后比较timestamp后继续丢弃....如此往复,最终导致通过NAT机器发起的conn_new(ip1, port1, ip2, port2)在TW状态终止的2MSl内都无法建立新的连接,对于机器B的用户表现就是连接迟迟无法建立成功。
    2. 高版本内核由于新的时间戳生成算法tcp: randomize tcp timestamp offsets for each connection 即便未使用NAT也会导致同一台机器不同socket之间timestamp非单调递增
  4. Linux从4.12版本内核开始已经移除了tcp_tw_recycle支持

文章开始时两个问题的答案

  1. 远端定义为ip+port,无论tcp_tw_reuse还是tcp_tw_recycle,针对回收TW连接对新连接的影响,都是指同一四元组代表的连接(src_ip, src_port, dst_ip, dst_port),在开启tcp_tw_recycle情况下,连接进入TW状态的2MSL时间内,所有收到的小于旧连接最终timestamp的包都会被直接丢弃。
  2. 客户端是指主动发起连接的一方,即TCP三次握手中发出首个SYN包的一方。

转载请注明出处,原文地址:https://www.cnblogs.com/AcAc-t/p/tcp_tw_reuse_and_tcp_tw_recycle_introduction.html

参考:

posted @ 2021-10-07 21:32  及时  阅读(2281)  评论(0编辑  收藏  举报