服务器端有许多TIME_WAIT状态会产生什么成本?

68
假设有一个客户端频繁地与服务器建立短暂的连接。如果客户端关闭连接,客户端会有很多处于 TIME_WAIT 状态的端口。由于客户端用完了本地端口,因此无法快速地进行新的连接尝试。
如果服务器关闭连接,我会在服务器端看到许多 TIME_WAIT。但是,这会造成任何伤害吗?客户端(或其他客户端)可以继续进行连接尝试,因为它永远不会用完本地端口,而服务器端的 TIME_WAIT 状态数量将增加。最终会发生什么?会发生什么不好的事情吗?(例如减速、崩溃、丢失连接等)
请注意,我的问题不是“TIME_WAIT 的目的是什么?”而是“如果服务器上有太多的 TIME_WAIT 状态会发生什么?”我已经知道在TCP/IP中关闭连接时会发生什么以及为什么需要 TIME_WAIT 状态。我不是在尝试解决问题,只是想知道潜在的问题是什么。
简单来说,假设 netstat -nat | grep :8080 | grep TIME_WAIT | wc -l 打印出 100000,会发生什么?操作系统的网络堆栈会减慢吗?会出现“打开文件过多”错误吗?还是只是无需担心?

一些系统在“32K TIME_WAIT”时出现问题。http://serverfault.com/a/212127/87017 - Pacerier
2
对于Linux,有一篇基于Webstone基准测试数据的论文。此外还有一篇名为“TCP中的TIME-WAIT状态及其对繁忙服务器的影响”的文章(https://scholar.google.com/scholar?cluster=2607037814764769062&hl=en&as_sdt=0,5&sciodt=0,5)。 - Pacerier
6个回答

66

TIME_WAIT 中的每个套接字都会在内核中消耗一些内存,通常比 ESTABLISHED 套接字少一些,但仍然很重要。如果数量足够大,可能会耗尽内核内存,或者至少会降低性能,因为该内存可以用于其他目的。假设已经正确关闭了套接字,TIME_WAIT 套接字不会保持打开的文件描述符,因此您不需要担心“打开文件过多”错误。

该套接字还会绑定特定的 src/dst IP 地址和端口,因此在 TIME_WAIT 时间间隔内无法重复使用它们。(这是 TIME_WAIT 状态的预期目的。)绑定端口通常不是问题,除非您需要使用相同的端口对重新连接。通常情况下,一方将使用临时端口,只有一方锚定到已知端口。但是,如果您在同两个 IP 地址之间反复频繁地连接,则大量的 TIME_WAIT 套接字可能会耗尽临时端口空间。请注意,这仅影响此特定 IP 地址对,不会影响与其他主机建立连接。


你确定这与Windows Server和其他操作系统也有关吗? - Pacerier
值得一提的是,通过为新套接字设置选项SO_REUSEADDR,您可以使用处于TIME_WAIT状态的套接字占用的端口。 - avernus

17

每个连接都由一个四元组(服务器IP、服务器端口、客户端IP、客户端端口)来标识。重要的是,TIME_WAIT连接(无论它们是在服务器端还是客户端)都占用其中一个这样的四元组。

对于客户端的TIME_WAIT,很容易看出为什么不能建立更多的连接——没有更多的本地端口了。然而,在服务器端也存在同样的问题——一旦单个客户端有64k个处于TIME_WAIT状态的连接,它就无法接受来自该客户端的任何新连接,因为它无法区分旧连接和新连接——这两个连接都由相同的四元组标识。在这种情况下,服务器应该只向来自该客户端的新连接尝试发送RST


在我的情况下到底发生了什么? - Vikram Saini

13

目前的发现:

即使服务器使用系统调用关闭套接字,如果它进入TIME_WAIT状态,它的文件描述符也不会被释放。当TIME_WAIT状态结束(即在2*MSL秒之后)文件描述符才会被释放。因此,太多的TIME_WAIT可能会导致服务器进程出现“打开的文件过多”错误。

我相信操作系统TCP/IP堆栈已经实现了适当的数据结构(例如哈希表),因此TIME_WAIT的总数不应影响操作系统TCP/IP堆栈的性能。只有处于TIME_WAIT状态的套接字所属的进程(服务器)会受到影响。


不确定这是正确的。我已经产生了数百个TIME_WAIT,但在sysctl fs.file-nr中并没有看到打开的文件描述符数量增加。 - c4il
1
@c4il,@trustin,为什么大家在讨论这个问题时都没有说明是哪个操作系统?具体的版本也会很有帮助。 - Pacerier
@trustin:有很多打开的文件描述符的原因是什么?你找到了吗? - Albin

2
如果您有许多来自许多不同客户端IP到服务器IP的连接,您可能会遇到连接跟踪表的限制。
请检查:
sysctl net.ipv4.netfilter.ip_conntrack_count
sysctl net.ipv4.netfilter.ip_conntrack_max

针对所有源IP/端口和目标IP/端口元组,跟踪表中只能有net.ipv4.netfilter.ip_conntrack_max。如果达到此限制,您将在日志中看到消息“nf_conntrack:table full,dropping packet。”并且服务器将不会接受新的传入连接,直到跟踪表中再次有空间。

这个限制可能会在临时端口用完之前就会影响到你。


0
在我的情况下,我运行了一个脚本来重复安排文件,我的产品进行一些计算并向客户端发送响应,即客户端正在进行重复的http调用以获取每个文件的响应。当约有150个文件被安排时,我的服务器套接字端口进入time_wait状态,并在客户端中抛出异常,该异常打开了一个http连接。
 Error : [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

结果是我的应用程序挂起了。我不知道可能是线程进入了等待状态还是发生了什么事情,但我需要杀死所有进程或重新启动我的应用程序以使其再次工作。

我尝试将等待时间缩短到30秒,因为默认情况下是240秒,但它没有起作用。

因此,总体影响是关键的,因为它使我的应用程序无法响应。


-2

看起来服务器可能会耗尽可分配给传入连接的端口(在现有的TIMED_WAIT期间)- 这是DOS攻击的情况。


7
服务器为什么会用完端口?服务器未为已接受的连接分配本地端口。这就是为什么服务器可以处理10万个并发连接的原因,忽略繁忙的CPU问题。 - trustin
4
当接受连接时,计算机会分配一个本地端口。在命令提示符下运行“netstat -a”,您将看到这些端口。我认为TIME_WAIT的原因是TCP数据包可能会以错误的顺序到达,因此端口不能立即关闭,以允许迟到的数据包到达。这意味着,确实有可能用尽端口。有缩短TIME_WAIT期限的方法,但风险在于如果超时时间太短,则先前连接的延迟到达的数据包可能被误认为是重新分配端口上新连接的数据包。 - Paul Ruane
3
如果您运行“netstat -nat”命令,则会看到由同一服务器套接字接受的连接具有相同的本地端口。因此,我猜测对于已接受的连接不会分配额外的本地端口? - trustin
1
@Trustin Lee:事实证明你是对的——TCP连接通过4元组(服务器地址、服务器端口、客户端地址、客户端端口)唯一标识,因此端口耗尽仅适用于一个(相当牵强的)情况,即所有连接的客户端IP和端口都相同。 - catwalk
2
当一个广泛使用的应用服务器连接到同一数据库以处理请求时,这并不是那么牵强。 - stu
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接