在 Linux 中更改 TCP RTO 值

obi*_*e91 12 linux tcp linux-kernel

我想更改连接的 TCP RTO (重传超时)值,我所做的一些阅读表明我可以这样做,但没有透露在哪里以及如何更改它。

我查看了/proc/sys/net/ipv4变量,但没有一个变量与 RTO 相关。如果有人能告诉我如何改变这个值,我将不胜感激。

Ada*_*m C 32

您不能专门更改 RTO 的原因是因为它不是静态值。相反(除了初始 SYN,自然)它基于每个连接的 RTT(往返时间)。实际上,它基于 RTT 的平滑版本和 RTT 方差,并在其中加入了一些常量。因此,它是每个 TCP 连接的动态计算值,我强烈推荐这篇文章,它对计算和 RTO 的一般情况进行了更详细的介绍。

同样相关的是RFC 6298,其中规定(以及许多其他内容):

每当计算 RTO 时,如果它小于 1 秒,那么 RTO 应该四舍五入到 1 秒。

那么内核是否总是将 RTO 设置为 1 秒?好吧,在 Linux 中,您可以通过运行以下ss -i命令来显示打开连接的当前 RTO 值:

State       Recv-Q Send-Q                                                  Local Address:Port     Peer Address:Port
ESTAB       0      0                                                           10.0.2.15:52861   216.58.219.46:http
     cubic rto:204 rtt:4/2 cwnd:10 send 29.2Mbps rcv_space:14600
ESTAB       0      0                                                           10.0.2.15:ssh          10.0.2.2:52586
     cubic rto:201 rtt:1.5/0.75 ato:40 cwnd:10 send 77.9Mbps rcv_space:14600
ESTAB       0      0                                                           10.0.2.15:52864   216.58.219.46:http
     cubic rto:204 rtt:4.5/4.5 cwnd:10 send 26.0Mbps rcv_space:14600
Run Code Online (Sandbox Code Playgroud)

以上是我使用 SSH 登录的 VM 的输出,并且有几个连接到 google.com。如您所见,RTO 实际上设置为 200-ish(毫秒)。您会注意到它没有四舍五入到 RFC 中的 1 秒值,您可能还认为它有点高。这是因为在 Linux 的 RTO 中存在最小(200 毫秒)和最大(120 秒)界限(我在上面链接的文章中对此有很好的解释)。

因此,您不能直接更改 RTO 值,但是对于有损网络(如无线),您可以尝试调整F-RTO(这可能已经启用,具体取决于您的发行版)。实际上,您可以调整与 F-RTO 相关的两个相关选项(这里有很好的总结):

net.ipv4.tcp_frto
net.ipv4.tcp_frto_response
Run Code Online (Sandbox Code Playgroud)

根据您尝试优化的内容,这些可能有用也可能没用。

编辑:跟进从评论中调整 TCP 的 rto_min/max 值的能力。

您无法更改 TCP 的全局最小 RTO(顺便说一句,您可以为 SCTP 更改 - 这些在 sysctl 中公开),但好消息是您可以调整每个路由上的 RTO 最小值基础。这是我在 CentOS 虚拟机上的路由表:

ip route
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15 
169.254.0.0/16 dev eth0  scope link  metric 1002 
default via 10.0.2.2 dev eth0
Run Code Online (Sandbox Code Playgroud)

我可以更改默认路由上的 rto_min 值,如下所示:

ip route change default via 10.0.2.2 dev eth0 rto_min 5ms
Run Code Online (Sandbox Code Playgroud)

现在,我的路由表如下所示:

ip route
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15 
169.254.0.0/16 dev eth0  scope link  metric 1002 
default via 10.0.2.2 dev eth0  rto_min lock 5ms
Run Code Online (Sandbox Code Playgroud)

最后,让我们启动一个连接并ss -i查看是否遵守了这一点:

ss -i
State       Recv-Q Send-Q                                               Local Address:Port                                                   Peer Address:Port   
ESTAB       0      0                                                        10.0.2.15:ssh                                                        10.0.2.2:50714   
     cubic rto:201 rtt:1.5/0.75 ato:40 cwnd:10 send 77.9Mbps rcv_space:14600
ESTAB       0      0                                                        10.0.2.15:39042                                                 216.58.216.14:http    
     cubic rto:15 rtt:5/2.5 cwnd:10 send 23.4Mbps rcv_space:14600
Run Code Online (Sandbox Code Playgroud)

成功!HTTP 连接(更改后)上的 rto 为 15 毫秒,而 SSH 连接(更改前)和以前一样为 200+。

我实际上喜欢这种方法 - 它允许您在适当的路由上设置较低的值,而不是在可能会破坏其他流量的全局设置。同样(参见ip 手册页),您可以调整路由的初始 rtt 估计和初始 rttvar(在计算动态 RTO 时使用)。虽然在调整方面它不是一个完整的解决方案,但我认为大多数重要的部分都在那里。您无法调整最大设置,但我认为这在任何情况下都不会那么有用。