简介: 压测场景下的 TIME_WAIT 解决

=====

某专有云我的项目具备压测场景,在Windows的压测机上用 LoadRunner 进行业务的压力测试,压测运行一段时间后呈现大量端口无奈调配的报错。
其实通过问题形容,以及 Windows的报错信息根本确定是压测机的问题。但可能起因较多,始终未能达成统一。所以,趁机剖析了客户端的压测机成为压测瓶颈的可能,除了CPU、网络、 I/O 等机器性能参数外,仍需思考网络协议引入的资源短缺问题。
注:以下内容的目标是理清TCP协定中比拟含糊的内容,对协定比拟相熟的能够疏忽。

  1. TIME_WAIT根底:RFC 793 TCP协定

==============================

家喻户晓, TCP存在三次握手,四次挥手过程。其具体设计的目标,简而言之,是为了在不稳固的物理网络环境中确保牢靠的数据传输;因而,TCP在具体实现中退出了很多异样情况的解决,整体协定就变得比较复杂。
要了解TCP协定,举荐浏览 RFC 793,可参考文后链接理解详情[1]。同时,也要了解“TCP state transition”状态机,如下图所示,可参考文后材料理解详情[2]。

图1. TCP状态转换图

本文仅针对 TW 在TCP协定中的作用进行探讨,不波及整体协定的剖析。四次挥手后的TIME_WAIT 状态,后续将以TW缩写代替。

2.1 TW 作用

首先,次要作用是保障TCP连贯敞开的可靠性。
思考下在四次挥手过程中,如果被动敞开方发送的LAST_ACK失落,那么被动敞开方会重传FIN。此时,如果被动敞开方对应的TCP Endpoint没有进入TW状态而是间接在内核中清理了,依据协定,被动敞开方会认为本人没有关上过这个端口,而以RST响应被动敞开方重传的FIN。最终该行为导致被动敞开方认为连贯异样敞开,在业务上可能会收到异样报错等状况。
其次,TW状态同时也能防止雷同的TCP端口收到在网络上前一个连贯的反复数据包。
实践上,数据包在网络上过期工夫对应即MSL(Maximal Segment Lifetime),随着操作系统的一直倒退,也有例外情况,这部分搜寻PAWS应该能够看到不少相似的文章阐明。
再次,端口进入 TW 状态 同时也防止了被操作系统疾速重复使用的可能。

2.2 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状态。

2.3 小结

TW 是为了保障 TCP 连贯失常终止(防止端口被疾速复用),也是为了保障网络中迷失的数据包失常过期(避免前一个连贯的数据包被谬误的接管)。
TW暗杀术,可参考文后材料理解详情[3]。

  1. 概念廓清

========

欢送探讨
几个可能比拟含糊的中央,明确如下:

  1. 作为连贯单方,客户端和服务器端的TCP Endpoint都可能进入 TW 状态(极其状况下,可能单方同时进入 TW 状态)。

该状况在逻辑上是成立的,可参考文后材料理解详情[4]。

  1. TW 是规范的一部分,不代表TCP端口或者连贯状态异样。(这个概念很重要,防止陷入某些不必要的陷阱。)
  2. CLOSE_WAIT 只管也是规范的一部分,但它的呈现预示着本端的 TCP Endpoint 处于半敞开状态,起因经常是应用程序没有调用 socket 相干的 close 或者 shutdown。可能的起因是应用程序仍有未发送实现的数据,该状况下CLOSE_WAIT 最终还是会隐没的。 具体形容这部分,长期有 CLOSE_WAIT 状态的端口迟缓累积,这种状况是须要引起留神的,累积到肯定水平,端口资源就不够了。

针对后面的 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"。

  1. TW 优化伎俩

===========

对于Linux,优化伎俩曾经进行了很多探讨了,以Centos为例,

  1. 在timestamps启用的状况下,配置 tcp_tw_reuse 和tcp_tw_recycle。

针对客户端,连贯申请发起方。
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]。

  1. 配置 max_tw_buckets,连贯申请发起方接管方通用,但须要留神这个选项自身有违 TW 设计的初衷。

net.ipv4.tcp_max_tw_buckets = 5000

  1. 配置 ip_local_port_range,连贯申请发起方。

net.ipv4.ip_local_port_range = 5000 65535

针对Windows ,材料较少,这边借之前的工作教训,总结如下:

  1. Windows Vista / Windows Server 2008 之前的操作系统,注册表

端口范畴:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
MaxUserPort = 0n65534
TW 超时工夫:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
TcpTimedWaitDelay = 0n30

  1. Windows 7 / Windows Server 2008 R2 及其之后的版本

端口范畴:
netsh int ipv4 set dynamicport tcp start=1025 num=64511
TW 超时工夫:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
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)
注:

  • 任何波及注册表的批改,只有重启机器才会失效。
  • 与 Linux不同,Windows 没有疾速回收机制,不存在疾速回收 TW 的可能,只能期待2MSL过期(即TcpTimedWaitDelay)。
  • Windows惟一能疾速回收TW状态的Endpoint 的状况:

新连贯申请的SEQ序列号>TW状态的Endpoint记录的SEQ序列号。
此时,内核会认为该 SYN 申请非法。 这里,这个TW 状态的 TCP Endpoint 肯定是在服务端(通过socket accept 关上的 服务端口)。(为了这个能力,Windows 的 RFC 1323 选项必须关上,内容能够自行搜寻。)

  1. 压测客户端无奈调配端口的起因剖析

====================

端口无奈调配有两种可能:

  • 齐全随机的动静端口申请,报错端口调配异样,根本是操作系统没有可用端口。
  • 指定端口的绑定申请报错端口调配异样,可能存在端口应用抵触问题。

针对第一种状况,首先须要通过 netstat -ano 进行疾速查看,剖析是否存在端口占满的状况,以及占满端口的TCP Endpoint状态。针对不同的状态,思考不同的计划。
比方,极其状况下,没有任何异样的服务器上,端口调配失败问题,可参考文后材料理解详情[5]。
以Windows操作系统TW状态Endpoint占满可用端口场景为例(在Linux上产生的可能性较低),剖析问题前须要大略理解 Windows 上端口调配原理。

  • Windows和Linux在动态分配端口的机制上有很大的不同。
  • Linux以浅显的了解应该是针对五元组的调配,即可能存在雷同的动静端口拜访不同服务器的服务端口。
  • Windows的动静端口调配实现基于Bitmap查找,无论拜访哪里,动静端口的池子最大为 1025 – 65536,即64511个。
  • 思考到最短30秒的 TW 超时工夫,如果依照 64511/29 = 2225 ports/s 的速度去创立端口,那么很可能在30秒后继续产生端口无奈调配的问题。
  • 这还是在连贯解决比拟疾速的状况下,如果连贯建设后不敞开,或者敞开工夫比拟久,创立端口的速度仍需继续降落来躲避端口问题。

了解了 TW 的造成起因,相应的解决方案也就比较清楚了。

  1. 升高应用程序创立端口的速度。思考连贯持续时间和TW超时工夫,计算绝对正当的连贯建设速度。不过,物理机操作系统、CPU/内存、网络IO等均可能影响连贯状态,准确计算很难;同时,就应用程序而言,升高端口创立速度须要额定的逻辑,可能性不大。
  2. 在这个压测场景下,通过减少机器的形式来变相缩小端口的需要。压测个别思考某个固定阈值下整体零碎的响应状况。在压力固定的状况下,能够通过扩散压力的形式来缩小端口资源的占用。
  3. 扭转连贯的行为,应用长久连贯(注:非HTTP的长连贯),例如针对500个并发,仅建设 500 个连贯。益处不言而喻,但害处也很显著,长久连贯不大合乎用户实在行为,压测后果可能失真。同时,该办法须要应用程序上的反对。
  4. 不让机器的TCP Endpoint进入TW状态,可参考以下2种计划。
    a) 不让该机器被动敞开连贯,而让对方被动敞开。这样,该主机进入被动敞开过程,在利用敞开TCP Endpoint之后,可间接开释端口资源。一些协定自身就有管制是否放弃连贯或者申请对方敞开连贯的行为或者参数,在思考这类问题的时候,能够适当进行利用。比方 HTTP 的长短连贯,可参考文后材料理解详情[4]。b) 通过TCP Reset强制开释端口。TCP Reset能够由任何一方收回,无论是发送方还是接管方,在看到TCP Reset之后会立即将对应TCP Endpoint拆除。

这里,可设置 socket 的 SO_LINGER选项,比方配置Nginx,可参考文后官网文档理解详情[6]。

图2:Nginx Lingering配置参考阐明

针对压测工具自身,官方网站上也有相似 ABRUPT 选项,可参考文后官网文档理解详情[7]。

图3:LoadRunner ABRUPT配置选项阐明

作者:陈鸽
原文链接
本文为阿里云原创内容,未经容许不得转载