简介:压测场景下的 TIME_WAIT 处理
某专有云项目具备压测场景,在Windows的压测机上用 LoadRunner 进行业务的压力测试,压测运行一段时间后出现大量端口无法分配的报错。
其实通过问题描述,以及 Windows的报错信息基本确定是压测机的问题。但可能原因较多,一直未能达成一致。所以,趁机分析了客户端的压测机成为压测瓶颈的可能,除了CPU、网络、 I/O 等机器性能参数外,仍需考虑网络协议引入的资源短缺问题。
注:以下内容的目的是理清TCP协议中比较模糊的内容,对协议比较熟悉的可以忽略。
众所周知, TCP存在三次握手,四次挥手过程。其具体设计的目的,简而言之,是为了在不稳定的物理网络环境中确保可靠的数据传输;因此,TCP在具体实现中加入了很多异常状况的处理,整体协议就变得比较复杂。
要理解TCP协议,推荐阅读 RFC 793,可参考文后链接了解详情[1]。同时,也要理解“TCP state transition”状态机,如下图所示,可参考文后资料了解详情[2]。
本文仅针对 TW 在TCP协议中的作用进行讨论,不涉及整体协议的分析。四次挥手后的TIME_WAIT 状态,后续将以TW缩写替代。
首先,主要作用是保证TCP连接关闭的可靠性。
考虑下在四次挥手过程中,如果主动关闭方发送的LAST_ACK丢失,那么被动关闭方会重传FIN。此时,如果主动关闭方对应的TCP Endpoint没有进入TW状态而是直接在内核中清理了,根据协议,主动关闭方会认为自己没有打开过这个端口,而以RST响应被动关闭方重传的FIN。最终该行为导致被动关闭方认为连接异常关闭,在业务上可能会收到异常报错等情况。
其次,TW状态同时也能避免相同的TCP端口收到在网络上前一个连接的重复数据包。
理论上,数据包在网络上过期时间对应即MSL(Maximal Segment Lifetime),随着操作系统的不断发展,也有例外情况,这部分搜索PAWS应该可以看到不少类似的文章说明。
再次,端口进入 TW 状态 同时也避免了被操作系统快速重复使用的可能。
当一台主机操作系统主动关闭TCP Endpoint(socket)时,该TCP Endpoint进入TW状态。以Windows为例,Windows内核会对 TCP Endpoint 数据结构进行相应清理,然后放入额外的 TW queue 中,设置2MSL 的定时器,等待定时器超时后调用对应的释放代码。Linux上的实现也是类似。
目前较多的说法是"TCP连接"进入TW ,但我们可能需要理解 "连接" 其实是抽象的概念。实际上"连接"在逻辑上存在,因为客户端和服务器端以及中间可能涉及的4层设备同时为一次传输创建了关联的TCP资源(Endpoint,或者 Session)。准确理解TW状态,即TCP EndpointTW进入TW状态。
TW 是为了保证 TCP 连接正常终止(避免端口被快速复用),也是为了保证网络中迷失的数据包正常过期(防止前一个连接的数据包被错误的接收)。
TW暗杀术,可参考文后资料了解详情[3]。
欢迎讨论
几个可能比较模糊的地方,明确如下:
该情况在逻辑上是成立的,可参考文后资料了解详情[4]。
针对前面的 TCP Endpoint 这个词语,可能很多人不太了解,这边也简单说明下:
在Windows 2008 R2之前,socket是用户态(user mode) 的概念,大多数Windows socket应用程序基本都基于Winsock开发,由中间层AFD.sys 驱动翻译成内核 tcpip.sys 协议栈驱动 所能接受的TCP Endpoint数据结构。在2008 R2之后,微软为了方便内核的网络编程,在Windows Kernel中提供WSK,即Winsock在内核的实现。文中提到的TCP Endpoint是在Windows内核中由TCPIP.sys驱动文件实现的TCP数据结构,也对应Linux上的socket。该文简单以 Endpoint 代指内核的"socket"。
对于Linux,优化手段已经进行了很多讨论了,以Centos为例,
针对客户端,连接请求发起方。net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_reuse = 1
针对服务器端,连接请求接收方net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1
注:tcp_tw_recycle的启用会带来一些 side effect,具体在NAT地址转换场景下,容易发生连接异常问题。
可参考文后资料了解详情[4]。
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 5000 65535
针对Windows ,资料较少,这边借之前的工作经验,总结如下:
端口范围:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
MaxUserPort = 0n65534
TW 超时时间:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
TcpTimedWaitDelay = 0n30
端口范围:netsh int ipv4 set dynamicport tcp start=1025 num=64511
TW 超时时间:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
TcpTimedWaitDelay = 0n30
Windows Server 2012 and earlier: 30-300 (decimal)
Windows 8 and earlier: 30-300 (decimal)
Windows Server 2012 R2 and later: 2-300 (decimal)
Windows 8.1 and later: 2-300 (decimal)
注:
新连接请求的SEQ序列号>TW状态的Endpoint记录的SEQ序列号。
此时,内核会认为该 SYN 请求合法。 这里,这个TW 状态的 TCP Endpoint 一定是在服务端(通过socket accept 打开的 服务端口)。(为了这个能力,Windows 的 RFC 1323 选项必须打开,内容可以自行搜索。)
端口无法分配有两种可能:
针对第一种情况,首先需要通过 netstat -ano 进行快速检查,分析是否存在端口占满的情况,以及占满端口的TCP Endpoint状态。针对不同的状态,考虑不同的方案。
比如,极端情况下,没有任何异常的服务器上,端口分配失败问题,可参考文后资料了解详情[5]。
以Windows操作系统TW状态Endpoint占满可用端口场景为例(在Linux上发生的可能性较低),分析问题前需要大概了解 Windows 上端口分配原理。
理解了 TW 的形成原因,相应的解决方案也就比较清楚了。
这里,可设置 socket 的 SO_LINGER选项,比如配置Nginx,可参考文后官方文档了解详情[6]。
针对压测工具本身,官方网站上也有类似 ABRUPT 选项,可参考文后官方文档了解详情[7]。
参考文档
[1] RFC 793:https://tools.ietf.org/html/rfc793
[2] IBM TCP state transition:https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.halu101/constatus.htm
[3] TIME-WAIT Assassination Hazards in TCP:https://tools.ietf.org/html/rfc1337
[4] Tengine健康检查引发大量TIME_WAIT堆积:https://developer.aliyun.com/article/781244
[5] CloudMonitor 引发的网络问题排查一则:https://developer.aliyun.com/article/682535
[6] 配置Nginx:http://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close
[7] ABRUPT选项:https://admhelp.microfocus.com/lr/en/2020_SP2-SP3/help/function_reference/Content/FuncRef/web/lrFR_web_set_sockets_option.htm?Highlight=web_set_socket_option#Shutdown
我们是阿里云智能全球技术服务-SRE团队,我们致力成为一个以技术为基础、面向服务、保障业务系统高可用的工程师团队;提供专业、体系化的SRE服务,帮助广大客户更好地使用云、基于云构建更加稳定可靠的业务系统,提升业务稳定性。我们期望能够分享更多帮助企业客户上云、用好云,让客户云上业务运行更加稳定可靠的技术。
原文链接:https://developer.aliyun.com/article/781757?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。