Skip to content

Commit

Permalink
posts(timewait): 补充解释更透彻的文章链接
Browse files Browse the repository at this point in the history
  • Loading branch information
Octobug committed Apr 18, 2024
1 parent 4a2ada6 commit 2609d07
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions posts/trans-tcp-time-wait-state-linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ hello
XXXXhello
```

在总结出上面这些现象后,我找了某云售后工程师咨询。对面询问我是否修改过服务器的 `net.ipv4.tcp_tw_reuse` 参数。我表示没有,同时也不知道这个参数的作用是什么。因此搜索了一番而找到上文提到的这篇文章,并且根据文章可以判断出问题在于启用了另外一个 ipv4 内核参数:`net.ipv4.tcp_tw_recycle`
在总结出上面这些现象后,我找了阿里云售后工程师咨询(阿里云的售后还是很专业的)。对面询问我是否修改过服务器的 `net.ipv4.tcp_tw_reuse` 参数。我表示没有,同时也不知道这个参数的作用是什么。因此搜索了一番而找到上文提到的这篇文章,并且根据文章可以判断出问题在于启用了另外一个 ipv4 内核参数:`net.ipv4.tcp_tw_recycle`

### 修改内核参数

Expand Down Expand Up @@ -330,15 +330,15 @@ $ ss -tan 'sport = :80' | awk '{print $(NF)" "$(NF-1)}' | \
### `net.ipv4.tcp_tw_reuse`
`TIME-WAIT` 状态可以防止延迟的数据包被无关的连接所接收。然而在某些情况下,可以假设新连接的数据包不会与旧连接的数据包混淆
`TIME-WAIT` 状态可以防止延迟的报文被无关的连接所接收。然而在某些情况下,可以假设新连接的报文不会与旧连接的报文混淆
[RFC1323](https://www.rfc-editor.org/rfc/rfc1323) 提出了一组 TCP 扩展,以改善在高带宽路径上的性能。其中一项是定义了一个新的 TCP 选项,它包含两个四字节的***时间戳字段***。第一个字段是发送该选项的 TCP 的时间戳时钟的当前值,而第二个字段是从远程主机接收到的最新时间戳。
通过启用 `net.ipv4.tcp_tw_reuse` 参数,Linux 会在新的***出站连接***的时间戳严格大于前一连接记录的最新时间戳时,重用处于 `TIME-WAIT` 状态的现有连接:这意味着在 `TIME-WAIT` 状态的出站连接只需等待一秒后就可以被重用。
这样做如何保证安全?`TIME-WAIT` 状态的首要目的是避免重复的数据包被不相关的连接接收。由于使用了时间戳,此类重复的数据包将带有过时的时间戳,因此会被丢弃。
这样做如何保证安全?`TIME-WAIT` 状态的首要目的是避免重复的报文被不相关的连接接收。由于使用了时间戳,此类重复的报文将带有过时的时间戳,因此会被丢弃。
第二个目的是确保远端不会因为丢失最后一个 *ACK* 包而处于 `LAST-ACK` 状态。远端将重传 *FIN* 数据包,直到
第二个目的是确保远端不会因为丢失最后一个 *ACK* 包而处于 `LAST-ACK` 状态。远端将重传 *FIN* 报文,直到
1. 等待超时,并中断连接;
2. 或者收到等待中的 *ACK*,并中断连接;
Expand All @@ -358,7 +358,7 @@ $ ss -tan 'sport = :80' | awk '{print $(NF)" "$(NF-1)}' | \
这个机制也依赖于前文提到的时间戳选项,但***同时影响入站和出站连接***。当服务器通常会先关闭连接时,这个机制会非常方便。[^tw_recycle]
此时 `TIME-WAIT` 状态会被设置更早的过期时间:它将在重传超时 *(RTO, Retransmission Timeout)* 间隔(根据 RTT 及其方差计算得出)之后被移除。可以使用 `ss` 命令观察当前连接使用的值:
此时 `TIME-WAIT` 状态会被设置更早的过期时间:它将在重传超时 *(RTO, Retransmission Timeout)* 间隔(根据 RTT (Round-Trip Time) 及其方差计算得出)之后被移除。可以使用 `ss` 命令观察当前连接使用的值:
```sh
$ ss --info sport = :2112 dport = :4057
Expand All @@ -367,7 +367,7 @@ ESTAB 0 1831936 10.47.0.113:2112 10.65.1.42:4057
cubic wscale:7,7 rto:564 rtt:352.5/4 ato:40 cwnd:386 ssthresh:200 send 4.5Mbps rcv_space:5792
```

为了保持 `TIME-WAIT` 状态所提供的保证,同时减小过期计时器的值,当一个连接进入 `TIME-WAIT` 状态时,最新的时间戳会被记录在一个专用结构体中,该结构体包含此前目标地址的各种参数。然后,除非 `TIME-WAIT` 状态已过期,如果来自远程主机的数据包不严格大于最新记录的时间戳, Linux 就会丢弃这些数据包
为了保持 `TIME-WAIT` 状态所提供的保证,同时减小过期计时器的值,当一个连接进入 `TIME-WAIT` 状态时,最新的时间戳会被记录在一个专用结构体中,该结构体包含此前目标地址的各种参数。然后,除非 `TIME-WAIT` 状态已过期,如果来自远程主机的报文不严格大于最新记录的时间戳, Linux 就会丢弃这些报文

```c
if (tmp_opt.saw_tstamp &&
Expand All @@ -384,7 +384,9 @@ if (tmp_opt.saw_tstamp &&
}
```

当远程主机是 ***NAT 设备***时,这个时间戳条件就会禁止 NAT 设备后面的某一台主机之外的所有其他主机在一分钟内进行连接,因为它们不共享相同的时间戳时钟。如有拿不准,最好禁用此选项,因为它会导致***难以检测******难以诊断***的问题。
当远程主机是 ***NAT 设备***时,这个时间戳条件就会禁止 NAT 设备后面的某一台主机之外的所有其他主机在一分钟内进行连接,因为它们不共享相同的时间戳时钟。如果拿不准,最好禁用此选项,因为它会导致***难以检测******难以诊断***的问题。

> 注:这里的解释不是很清楚,补充 `兔子先生` 一篇相关博文的链接:[好朋友 TIME_WAIT](https://liupzmin.com/2020/02/26/network/tcp-time-wait/)
📌 *更新 (2017-09)*

Expand All @@ -404,4 +406,4 @@ if (tmp_opt.saw_tstamp &&

最后引用 [W. Richard Stevens](http://www.kohala.com/start/)[《Unix 网络编程》](https://www.amazon.com/Unix-Network-Programming-Volume-Networking/dp/0131411551)中的一段话:

> *`TIME_WAIT` 状态是我们的朋友,它可以帮助我们(即是,使旧的重复数据包在网络中过期)。与其试图避免该状态,不如真正地理解它。*
> *`TIME_WAIT` 状态是我们的朋友,它可以帮助我们(即是,使旧的重复报文在网络中过期)。与其试图避免该状态,不如真正地理解它。*

0 comments on commit 2609d07

Please sign in to comment.