如何为两个节点之间的高频连接调整 TCP

Chr*_*oph 8 reverse-proxy load-balancing tcp f5-big-ip high-load

过去几天我一直在挠头,试图为以下问题提出解决方案:

在我们的数据中心,我们有一个运行在 BigIP 硬件上的 F5,它充当来自全国各地不同办公地点的客户端机器的 HTTPS 请求的单一入口点。F5 终止 TLS,然后将所有请求转发到两个 Traefik 负载均衡器,后者将请求路由到各种服务实例(Traefik 节点在 Red Hat Enterprise 上的 Docker 中运行,但我认为这与我的问题无关)。从吞吐量、CPU 和内存的角度来看,这三个网络组件完全有能力处理大量请求和流量,并有足够的备用容量。

但是,我们注意到客户端发出的 HTTP(S) 请求频繁出现 1000 毫秒的延迟,尤其是在高负载时间。我们将问题跟踪到以下根本原因:

  • 在高负载期间,F5“客户端”以高频率(可能每秒 100+)向 Traefik“服务器”节点发起新的 TCP 连接。
  • 当 HTTP 响应返回时,这些连接在 Traefik“服务器”端终止。
  • 每个关闭的连接在 Traefik 主机上保持 TIME_WAIT 状态 60 秒。
  • 当 F5 发起新连接时,它会从其临时端口范围中随机选择一个可用端口。
  • 有时(通常在高负载期间),Traefik 中已经有一个处于 TIME_WAIT 状态的连接,具有相同的源 IP + 端口、目标 IP + 端口组合。发生这种情况时,Traefik 主机上的 TCP 堆栈 (?) 会忽略第一个 SYN 数据包。注意:RFC 6056称此为 instance-ids 的冲突
  • 1000 毫秒后,重传超时 (RTO) 机制在 F5 上启动并重新发送 SYN 数据包。这次 Traefik 主机接受了连接并正确完成了请求。

显然,那些 1000 毫秒的延迟是绝对不能接受的。所以到目前为止我们已经考虑了以下解决方案:

  1. 减少 F5 中的 RTO 以更快地重新传输,例如减少到 200 毫秒。
  2. 减少 net.ipv4.tcp_fin_timeout 以更快地关闭废弃的 TIME_WAIT连接。
    更新:这仅适用于对方放弃的连接,当没有返回 FIN 时。它对处于 TIME_WAIT 状态的连接没有任何影响。
  3. 启用 net.ipv4.tcp_tw_reuse:对传入连接无用。
  4. 启用 net.ipv4.tcp_tw_recycle:如果客户端发送随机 TCP 时间戳,则 AFAIK 是禁忌的。矛盾的信息(包括经验证据)是否从 Linux 中删除了此功能。另外,一般建议不要乱用。
  5. 添加更多源 IP 和/或让 Traefik 侦听多个端口以增加 IP/端口元组中的排列数量。

我会丢弃#1,因为那只是创可贴。延迟仍然发生,只是不太明显。#3 无论如何都不会产生任何影响,#4 很可能会使系统无法正常工作。剩下#2和#5。

但根据我看了几十篇帖子和技术文章后了解到的,两者最终只会减少那些“碰撞”的机会。因为,最终阻止发送方 F5(伪)随机选择在目标 Traefik 主机上仍处于 TIME_WAIT 状态的临时端口、源 IP 和目标端口的组合,无论 fin_timeout 设置有多短(哪个无论如何都应该保持在几秒范围内)?我们只会减少碰撞的可能性,而不是消除它。

经过我所有的研究和巨大的 Web 应用程序时代,我真的很惊讶这个问题在 Web 上没有更多的讨论(和可用的解决方案)。我非常感谢您关于在 TCP 领域是否有更好、更系统的解决方案来推动碰撞发生接近零的想法和想法。我正在考虑 TCP 配置的思路,该配置将允许 Traefik 主机立即接受新连接,尽管旧连接处于 TIME_WAIT 状态。但截至目前,没有运气找到。

随意的想法和要点:

  • 在这一点上,改变我们的各种内部应用程序以使用运行时间更长的 HTTP(S) 连接来减少每秒请求/连接的数量是不可行的。
  • F5 和 Traefik 的网络架构是不可讨论的,不能改变。
  • 我最近调查了 Windows 客户端上的临时端口选择。该算法似乎是顺序的,而不是随机的。最大化端口被重用的时间,降低安全性。
  • 在对其他空闲系统进行负载测试期间,我们每秒生成约 100 个 HTTP 请求/连接。尽管 F5 配置为使用超过 60k 的临时端口,但第一次冲突已经发生在几秒钟之后(比如在总共 2000 个请求之前)。我认为这是由于端口选择算法的伪随机特性,它似乎在避免实例 ID 冲突方面做得很差。
  • Traefik 主机在 SYN 数据包重传时接受 TCP 连接这一事实可能是TCP 实现的一个特性。RFC6056 谈到了TIME_WAIT 暗杀,这可能与此有关。

更新:根据星实验,net.ipv4.tcp_fin_timeout 设置不影响 TIME_WAIT 状态,只影响 FIN_WAIT_2 状态。根据Samir Jafferali 的说法,在 Linux 系统(包括我们的 Red Hat Linux)上,TIME_WAIT 时间段在源代码中是硬编码的,无法配置。根据来源,在 BSD 上它是可配置的,但我还没有验证这一点。

poi*_*ige 4

在我们的数据中心,我们有一个在 BigIP 硬件上运行的 F5,它充当来自我们全国各地办公地点的客户端计算机的HTTPS 请求的单一入口点

如果这个单点(前端)在将连接向下传递到后端时保持单一,为什么您想知道这些问题?特别是如果连接强度“可能每秒超过 100 个”。

您的设置基本上是将一组基数较高的集合压缩到另一组基数明显较低的集合中。

最终只会减少那些“碰撞”的机会

这是分组交换网络如何工作的基础。比如说,在以太网级别也存在冲突。随机性是不可避免的,TCP/IP 正在处理它。事实上,IP 协议本身的构建并没有考虑到 LAN(但在那里仍然可以很好地工作)。

所以是的,“添加更多源 IP 和/或让 Traefik 监听多个端口”是相当合理的遵循方式。