我们有一个应用程序对远程 Web 服务器/服务进行大量调用。客户端应用程序是 Linux(Red Hat 5)上的 JBoss/Java,远程服务器是 Windows 2008。有一个 Cisco ACE,但没有进行 NAT。
我们注意到,当 Linux/JBoss 重用源端口进行 HTTP 调用时,我们会收到“连接被拒绝”的消息。这是因为客户端在几分钟内重用了上述源端口。
在两端运行 tcpdump/wireshark 时我看到的是这样的:
请求#1:源端口 6666,目标端口 80
客户端 --> Syn 服务器 --> Syn ACK 客户端 --> ACK 客户端 --> GET / 服务器 --> 返回数据 客户端 --> ACK 服务器 --> FIN ACK 客户端 --> FIN ACK 服务器 --> ACK
请求#2:相同的源和目标端口成功。
请求#3:相同的源和目标端口成功。
请求#4:相同的源端口和目标端口,但这次失败(“连接被拒绝”),如下所示:
客户端-->SYN 客户端-->SYN(重传) 客户端-->RST,ACK
服务器看到两个 SYN,但从不发送 ACK 或 RST(它看到来自客户端的 RST)。
经过一番搜索后,我发现 TCP 时间戳存在潜在问题。我们确保 ACE 允许这些时间戳通过,我可以验证 Windows 是否看到它们。我还看到服务器/Windows 端的连接处于 TIME_WAIT 状态(但即使在第一次 GET 成功、第二次和第三次成功之后,我也看到了这种情况)。客户端的端口未打开或处于 TIME_WAIT 状态。
我一直在研究的一个方法是将 Windows 端的 TcpTimedWaitDelay 注册表项减少到 30 秒。我还没有这样做或测试过,但我认为如果我们的问题存在,它应该会起作用。
我已将客户端/Linux 端的端口增加到 15000 - 60000(从默认值 30000 增加到 60000),但无济于事(只是希望可用端口的增加会因使用源端口的随机性而导致更长的延迟时间)
我发现奇怪的是,服务器/Windows 端看到 SYN 已经通过但没有响应,这让我认为 SYN 来自上一个会话或其他东西。
我不确定我是否喜欢这个,但我想知道是否有办法告诉 Linux 不要重复使用最近使用过的源端口?就像逻辑中的某种延迟(如果有的话)?
这并不是说我们用完了可用的端口或什么的,但有时,因为它是随机的,所以源端口会在几分钟内被重复使用,这时我们就会看到问题。
大家对此还有其他想法吗?
谢谢!
更新
我在 Windows 服务器上将 TcpTimedWaitDelay 设置为 30 秒。只要在 30 秒之后再次使用源端口进行呼叫,就不会出现问题。
我相信 ACE 在某些方面仍然应受到指责,它可能是某种 SYN 攻击保护(ACE 是一种安全设备),如果我绕过 ACE,就不会出现任何问题。
但目前将 2MSL 设置为 30 秒似乎是一个足够好的解决方案。
答案1
我对 Windows 套接字循环了解不够,无法回答这个问题,但我猜测服务器关闭了连接,并且套接字处于TIME_WAIT
无法再次使用的状态,直到它们过期为止。
解决这个问题的“正确”方法是添加更多元组 - 增加客户端上的传出端口(您已经完成),在服务器上添加监听端口,在您的接口上添加 IP 别名,并让应用程序使用这些额外的 IP /端口。
一种“不太正确”的方法是减少 TW 超时,我认为您正在这样做TcpTimedWaitDelay
。
一种“不太正确但仍然很流行”的方法是启用套接字回收,Linux 有选项tw_reuse
,tw_recycle
也许 Windows 也有等效的选项。
最后两个选项违反了 TCP RFC。也许 ACE 对此有意见?