我们有几个生产系统最近被转换成虚拟机。我们的一个应用程序经常访问 MySQL 数据库,并且对于每个查询,它都会创建一个连接、查询并断开该连接。
这不是合适的查询方式(我知道),但我们有似乎无法绕过的限制。无论如何,问题是这样的:当机器是物理主机时,程序运行良好。一旦转换为虚拟机,我们就会注意到与数据库的间歇性连接问题。在某一时刻,TIME_WAIT 中有 24000 多个套接字连接(在物理主机上,我看到的最多是 17000 个 - 不太好,但不会造成问题)。
我希望这些连接能够被重复使用,这样我们就不会看到连接问题,因此:
问题:
将 tcp_tw_reuse 的值设置为 1 可以吗?有什么明显的危险?我有什么理由应该这样做吗绝不做吗?
另外,还有其他方法可以让系统(RHEL/CentOS)防止这么多连接进入 TIME_WAIT,或者让它们被重复使用吗?
最后,改变 tcp_tw_recycle 会有什么作用,这对我有帮助吗?
提前致谢!
答案1
您可以安全地减少时间,但您可能会遇到网络上不正确关闭的连接问题,从而导致数据包丢失或抖动。我不会从 1 秒开始调整,而是从 15-30 秒开始,然后逐步减少。
此外,您确实需要修复您的应用程序。
RFC 1185在第3.2节中有很好的解释:
当 TCP 连接关闭时,TIME-WAIT 状态下的 2*MSL 延迟会使套接字对占用 4 分钟(参见 [Postel81] 的 3.5 节)。基于 TCP 构建的应用程序在关闭一个连接并打开一个新连接时(例如,使用流模式的 FTP 数据传输连接),每次都必须选择一个新的套接字对。此延迟有两个不同的目的:
(a) Implement the full-duplex reliable close handshake of TCP. The proper time to delay the final close step is not really related to the MSL; it depends instead upon the RTO for the FIN segments and therefore upon the RTT of the path.* Although there is no formal upper-bound on RTT, common network engineering practice makes an RTT greater than 1 minute very unlikely. Thus, the 4 minute delay in TIME-WAIT state works satisfactorily to provide a reliable full-duplex TCP close. Note again that this is independent of MSL enforcement and network speed. The TIME-WAIT state could cause an indirect performance problem if an application needed to repeatedly close one connection and open another at a very high frequency, since the number of available TCP ports on a host is less than 2**16. However, high network speeds are not the major contributor to this problem; the RTT is the limiting factor in how quickly connections can be opened and closed. Therefore, this problem will no worse at high transfer speeds. (b) Allow old duplicate segements to expire. Suppose that a host keeps a cache of the last timestamp received from each remote host. This can be used to reject old duplicate segments from earlier incarnations of the
*注:有人可能会说,发送 FIN 的一方知道自己需要多大的可靠性,因此它应该能够确定 FIN 接收方的 TIME-WAIT 延迟长度。这可以通过 FIN 段中的适当 TCP 选项来实现。
connection, if the timestamp clock can be guaranteed to have ticked at least once since the old conennection was open. This requires that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender's timestamp clock. Note that this is a variant on the mechanism proposed by Garlick, Rom, and Postel (see the appendix), which required each host to maintain connection records containing the highest sequence numbers on every connection. Using timestamps instead, it is only necessary to keep one quantity per remote host, regardless of the number of simultaneous connections to that host.
答案2
这并没有回答你的问题(而且已经晚了 18 个月),但是建议了另一种让你的旧应用程序重用端口的方法:
在系统上设置tcp_tw_reuse
(或)的一个有用替代方法是将共享库(使用)插入到您的应用中;然后该库可以允许重用端口。这使您的旧应用允许端口重用,而不会在系统上的所有应用上强制执行此操作(无需修改您的应用),从而限制了调整的影响。例如,tcp_tw_recycle
LD_PRELOAD
LD_PRELOAD=/opt/local/lib/libreuse.so ./legacy_app
这个共享库应该拦截该socket()
调用,调用真正的套接字(),并在返回的套接字上设置 SO_REUSEADDR 和/或 SO_REUSEPORT。看看http://libkeepalive.sourceforge.net有关如何执行此操作的示例(这将打开 keepalive,但打开 SO_REUSEPORT 非常相似)。如果您行为不当的旧版应用程序使用 IPv6,请记住将第 55 行libkeepalive.c
从
if((domain == PF_INET) && (type == SOCK_STREAM)) {
到
if(((domain == PF_INET) || (domain == PF_INET6)) && (type == SOCK_STREAM)) {
如果您遇到困难,请给我发送电子邮件,我会编写代码并将其发送给您。
答案3
我认为将该值更改为 1 是可以的。更合适的方法可能是使用以下命令:
[root@server]# sysctl -w net.ipv4.tcp_tw_reuse=1
据我所知,没有明显的危险,但谷歌快速搜索后,出现了以下结果关联这证实了这tcp_tw_reuse
是比更好的选择tcp_tw_recycle
,但无论如何都应谨慎使用。
答案4
如果处于 TIME WAIT 状态,则无法重用连接。如果应用程序和 MySQL 之间的网络没有数据包丢失,则可以降低超时时间。
然而最好的解决方案是使用数据库和连接池的持久连接。