服务器端的许多 TIME_WAIT 成本是多少?
Posted
技术标签:
【中文标题】服务器端的许多 TIME_WAIT 成本是多少?【英文标题】:What is the cost of many TIME_WAIT on the server side? 【发布时间】:2010-12-20 16:29:54 【问题描述】:假设有一个客户端与服务器建立了很多短期连接。
如果客户端关闭连接,客户端会有很多TIME_WAIT
状态的端口。由于客户端用完了本地端口,因此无法快速尝试新的连接。
如果服务器关闭连接,我会在服务器端看到很多TIME_WAIT
s。然而,这有什么害处吗?客户端(或其他客户端)可以继续尝试连接,因为它永远不会用完本地端口,并且TIME_WAIT
状态的数量将在服务器端增加。最终会发生什么?有什么不好的事情发生吗? (减速、崩溃、断开连接等)
请注意,我的问题不是“TIME_WAIT
的目的是什么?”但是“如果服务器上有这么多TIME_WAIT
状态会怎样?”我已经知道在 TCP/IP 中关闭连接时会发生什么,以及为什么需要TIME_WAIT
状态。我不是想解决它,只是想知道它的潜在问题是什么。
简单地说,假设netstat -nat | grep :8080 | grep TIME_WAIT | wc -l
打印100000
。会发生什么?操作系统的网络堆栈会变慢吗? “打开的文件太多”错误?或者,没有什么可担心的?
【问题讨论】:
某些系统在“32KTIME_WAIT
”serverfault.com/a/212127/87017 上发现问题
对于 linux 有一个 paper 基于通过 Webstone 基准测试的数据。还有“The TIME-WAIT
state in TCP and its effect on busy servers”。
【参考方案1】:
看起来服务器可能会用完端口来分配传入连接(在现有 TIMED_WAIT 的持续时间内)——这是 DOS 攻击的一个案例。
【讨论】:
为什么服务器会耗尽端口?服务器没有为接受的连接分配本地端口。这就是为什么服务器可以处理 100k 并发连接,而将繁忙的 CPU 问题放在一边。 确实为接受的连接分配了一个本地端口,从命令提示符运行'netstat -a',你会看到这些。我相信 TIME_WAIT 的原因是 TCP 数据包可能以错误的顺序到达,因此不能立即关闭端口以允许迟到的数据包到达。这意味着确实有可能耗尽端口。有一些方法可以缩短 TIME_WAIT 周期,但风险在于,如果超时时间较短,那么来自先前连接的迟到数据包可能会被误认为是来自回收端口上新连接的数据包。 如果你运行'netstat -nat',你会看到同一个服务器套接字接受的连接具有相同的本地端口。因此我猜没有为接受的连接分配额外的本地端口? @Trustin Lee:事实证明你是对的 - 一个 tcp 连接由一个 4 元组(服务器地址、服务器端口、客户端地址、客户端端口)唯一标识,因此端口耗尽仅适用于(相当做作)客户端 ip 和端口对于所有连接都相同的情况。 当一个频繁使用的应用服务器连接到同一个数据库来处理请求时,这不是人为的。【参考方案2】:目前的调查结果:
即使服务器使用系统调用关闭了套接字,如果它进入TIME_WAIT状态,它的文件描述符也不会被释放。文件描述符将在 TIME_WAIT 状态消失后(即 2*MSL 秒后)释放。因此,过多的TIME_WAIT可能会导致服务器进程出现'too many open files'错误。
我相信 OS TCP/IP 堆栈已使用适当的数据结构(例如哈希表)实现,因此 TIME_WAIT 的总数不应影响 OS TCP/IP 堆栈的性能。只有拥有处于 TIME_WAIT 状态的套接字的进程(服务器)会受到影响。
【讨论】:
不确定是否属实。我已经产生了数百个 TIME_WAIT 但没有看到 sysctl fs.file-nr 中打开的文件描述符的数量增加。 @c4il,@trustin,为什么每个人都在讨论这个而不说明.. 哪个操作系统?特定版本也会有所帮助。 @trustin : 很多打开文件描述符的原因是什么,你找到了吗?【参考方案3】:每个连接都由一个元组标识(服务器 IP、服务器端口、客户端 IP、客户端端口)。至关重要的是,TIME_WAIT
连接(无论它们是在服务器端还是在客户端)每个都占用这些元组之一。
使用客户端的TIME_WAIT
s,很容易看出为什么不能建立更多的连接——你没有更多的本地端口。但是,同样的问题也适用于服务器端 - 一旦它在 TIME_WAIT
状态下拥有 64k 个连接对于单个客户端,它就无法接受来自该客户端的更多连接,因为它无法区分旧连接和新连接 - 两个连接都由同一个元组标识。在这种情况下,服务器应该只将RST
s 发送回来自该客户端的新连接尝试。
【讨论】:
在我的情况下到底发生了什么【参考方案4】:TIME_WAIT
中的每个套接字都会消耗内核中的一些内存,通常比ESTABLISHED
套接字少一些,但仍然很重要。足够大的数字可能会耗尽内核内存,或者至少会降低性能,因为该内存可以用于其他目的。 TIME_WAIT
套接字不保存打开的文件描述符(假设它们已正确关闭),因此您不必担心“打开的文件过多”错误。
套接字还绑定了特定的src
/dst
IP 地址和端口,因此在TIME_WAIT
间隔期间不能重复使用。 (这是TIME_WAIT
状态的预期目的。)除非您需要使用相同的端口对重新连接端口,否则绑定端口通常不是问题。大多数情况下,一侧将使用临时端口,只有一侧锚定到众所周知的端口。但是,如果您在相同的两个 IP 地址之间反复频繁地连接,大量的TIME_WAIT
套接字可能会耗尽临时端口空间。请注意,这只影响这个特定的 IP 地址对,不会影响与其他主机的连接。
【讨论】:
您确定这也与 Windows Server 和其他操作系统有关吗? 值得一提的是,通过为一个新的socket设置选项SO_REUSEADDR,你可以使用TIME_WAIT状态下被socket(s)占用的端口。【参考方案5】:如果您有很多从许多不同客户端 IP 到服务器 IP 的连接,您可能会遇到连接跟踪表的限制。
检查:
sysctl net.ipv4.netfilter.ip_conntrack_count
sysctl net.ipv4.netfilter.ip_conntrack_max
在所有 src ip/port 和 dest ip/port 元组中,跟踪表中只能有 net.ipv4.netfilter.ip_conntrack_max。如果达到此限制,您将在日志中看到一条消息“nf_conntrack:表已满,正在丢弃数据包。”并且服务器不会接受新的传入连接,直到跟踪表中再次有空间。
这个限制可能会在临时端口用完之前很久。
【讨论】:
【参考方案6】:在我的场景中,我运行了一个重复调度文件的脚本,我的产品进行一些计算并向客户端发送响应,即客户端正在进行重复的 http 调用以获取每个文件的响应。当大约 150 个文件被安排在套接字端口时我的服务器进入 time_wait 状态,并且在打开 http 连接的客户端中引发异常,即
Error : [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
结果是我的应用程序挂起。我不知道可能是线程已进入等待状态或发生了什么,但我需要终止所有进程或重新启动我的应用程序以使其再次工作。
我尝试将等待时间减少到 30 秒,因为默认为 240 秒,但它不起作用。
所以基本上整体影响很关键,因为它使我的应用程序无响应
【讨论】:
以上是关于服务器端的许多 TIME_WAIT 成本是多少?的主要内容,如果未能解决你的问题,请参考以下文章
[tcp] 服务端大量close_wait 和 time_wait状态