我在配置文件中将 tcp_tw_recycle/reuse 都设置为 1。
这样做会产生什么后果?
如果重复使用 TCP 套接字,是否会带来安全风险?即两个不同的连接都可能发送数据?
它是否适合短暂连接且重新连接机会很小的连接?
答案1
默认情况下,当和都tcp_tw_reuse
被tcp_tw_recycle
禁用时,内核将确保TIME_WAIT
状态中的套接字将保持该状态足够长的时间——足够长的时间以确保属于未来连接的数据包不会被误认为是旧连接的后期数据包。
启用时tcp_tw_reuse
,套接字TIME_WAIT
可以在过期之前使用,并且内核将尝试确保 TCP 序列号不会发生冲突。如果您启用tcp_timestamps
(又名 PAWS,即 Protection Against Wrapped Sequence Numbers),它将确保不会发生这些冲突。但是,您需要在两个都结束(至少,这是我的理解)。请参阅tcp_twsk_unique 的定义了解血腥细节。
当您启用时tcp_tw_recycle
,内核会变得更加激进,并将对远程主机使用的时间戳做出假设。它将跟踪每个远程主机使用的最后一个时间戳(处于连接状态TIME_WAIT
),并允许在时间戳正确增加的情况下重新使用套接字。但是,如果主机使用的时间戳发生变化(即时间回溯),SYN
将被默默丢弃,并且连接不会建立(您将看到类似于“连接超时”的错误)。如果您想深入了解内核代码,tcp_timewait_state_process 的定义可能是一个很好的起点。
现在,时间戳不应该回到过去;除非:
- 主机重新启动(但是,当它重新启动时,
TIME_WAIT
套接字可能已经过期,所以这不是一个问题); - 该 IP 地址很快会被其他东西重用(
TIME_WAIT
一些连接会保留一段时间,但其他连接可能会被删除TCP RST
,从而释放一些空间); - 网络地址解读(或是一个智能防火墙)参与到连接中间。
在后一种情况下,您可以在同一个 IP 地址后面拥有多个主机,因此,时间戳序列会有所不同(或者,防火墙会在每个连接时随机化时间戳)。在这种情况下,某些主机将随机无法连接,因为它们被映射到TIME_WAIT
服务器存储桶具有较新时间戳的端口。这就是为什么文档会告诉您“由于此设置,NAT 设备或负载平衡器可能会开始丢帧”。
有些人建议不管tcp_tw_recycle
,但允许tcp_tw_reuse
并降低tcp_timewait_len
。 我同意 :-)
答案2
我刚刚被它咬了一口,所以也许有人可以从我的痛苦和折磨中受益。首先,这是一个包含大量信息的复杂链接: http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html
尤其:
缺乏文档的结果是,我们发现许多调整指南建议将这两个设置都设置为 1,以减少 TIME-WAIT 状态中的条目数。但是,如 tcp(7) 手册页所述,net.ipv4.tcp_tw_recycle 选项对于面向公众的服务器来说相当成问题,因为它无法处理来自同一 NAT 设备后面的两台不同计算机的连接,这是一个难以检测且会给您带来麻烦的问题:
我曾经非常成功地启用了这些功能,以提供尽可能低的延迟,从客户端到 MySql NDB 集群的 haproxy 连接。这是在私有云中,任何连接之间都没有任何形式的 NAT。这个用例很有意义,尽可能降低 radius 客户端通过 haproxy 访问 NDB 的延迟。它做到了。
我又在面向公众的 haproxy 系统上做了一遍,对 Web 流量进行负载平衡,并没有真正研究其影响(很蠢,对吧?!),经过多次故障排除和追踪发现:
- 这会给通过 NAT 连接的客户端带来混乱。
- 它几乎不可能被识别,因为它是完全随机的、间歇性的,并且症状会在与客户 B 完全不同的时间(或不时间)袭击客户 A,等等。
在客户端,他们会发现一段时间内不再收到对 SYN 数据包的响应,有时候是零零星星的,有时候是很长时间。同样,这种情况是随机的。
以下是我最近痛苦经历的简短故事,无论角色如何,都不要管这些,在面向公众的服务器上禁用它们!
答案3
从‘man 7 tcp’你会看到这个:
tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)
Enable fast recycling of TIME_WAIT sockets. Enabling this option is not recommended since this causes problems when working with NAT
(Network Address Translation).
tcp_tw_reuse (Boolean; default: disabled; since Linux 2.4.19/2.6)
Allow to reuse TIME_WAIT sockets for new connections when it is safe from protocol viewpoint. It should not be changed without
advice/request of technical experts.
没什么帮助。这个问题也有一些很好的见解:
https://stackoverflow.com/questions/6426253/tcp-tw-reuse-vs-tcp-tw-recycle-which-to-use-or-both
但没有关于为什么重用比回收更安全的具体信息。基本答案是,如果已经有一个处于 TIME_WAIT 状态且具有相同 TCP 参数的套接字,并且该套接字处于不再需要进一步流量的状态(我相信这是在发送 FIN 时),则 tcp_tw_reuse 将允许使用相同的套接字。另一方面,tcp_tw_recycle 将只重用处于 TIME_WAIT 状态且具有相同参数的套接字,而不管其状态如何,这可能会使可能期待不同数据包的状态防火墙感到困惑。
可以通过设置 SO_REUSEADDR 套接字选项在代码中选择性地完成 tcp_tw_reuse,man 7 socket
如下所示:
SO_REUSEADDR
Indicates that the rules used in validating addresses supplied in a bind(2) call should allow reuse of local addresses. For AF_INET
sockets this means that a socket may bind, except when there is an active listening socket bound to the address. When the listening
socket is bound to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address. Argument is
an integer boolean flag.