这个问题的一些初始背景。目前,我有一个应用程序集群部署在 ALB 后面,该集群与应用程序保持持久的保持活动连接。此应用程序处于持续的高负载状态,并且必须具有非常高的正常运行时间。ALB 已从此服务发回 502 Bad Gateway 状态代码。深入挖掘并在受影响的实例上进行 pcap 捕获和 sysdig 捕获后,我们看到以下内容(按事件顺序排序):
19:51:26.881806 10.23.34.195 10.23.67.39 HTTP 1068 POST /api HTTP/1.1 (application/json)
19:51:26.881838 10.23.67.39 10.23.34.195 TCP 66 80→52026 [ACK] Seq=7201 Ack=19033 Win=67072 Len=0 TSval=240987 TSecr=1566420
19:51:27.018305861 0 node (2989) > writev fd=120(<4t>10.23.34.195:52026->172.17.0.2:3000) size=400
19:51:27.018326 10.23.67.39 10.23.34.195 HTTP 466 HTTP/1.1 200 OK (application/json)
19:51:27.018341806 0 node (2989) < writev res=400 data=HTTP/1.1 200 OK..Content-Type: application/json; charset=
19:51:27.018601 10.23.34.195 10.23.67.39 TCP 66 52026→80 [ACK] Seq=19033 Ack=7601 Win=47360 Len=0 TSval=1566454 TSecr=241021
19:51:32.042525 10.23.34.195 10.23.67.39 HTTP 1066 POST /api HTTP/1.1 (application/json)
19:51:32.042538 10.23.67.39 10.23.34.195 TCP 66 80→52026 [ACK] Seq=7601 Ack=20033 Win=69120 Len=0 TSval=242277 TSecr=1567710
19:51:32.066469320 0 node (2989) > close fd=120(<4t>10.23.34.195:52026->172.17.0.2:3000)
19:51:32.066470002 0 node (2989) < close res=0
19:51:32.066487 10.23.67.39 10.23.34.195 TCP 66 80→52026 [RST, ACK] Seq=7601 Ack=20033 Win=69120 Len=0 TSval=242283 TSecr=1567710
如上所述,我们的 nodejs 应用程序在保持活动连接上达到 5 秒不活动状态(默认保持活动超时期限),然后接收网络请求,然后关闭套接字,最后使用 RST 响应排队的网络请求。
因此,看起来 502 是由于竞争条件引起的,在 TCP 拆除期间或之间从负载均衡器接收到新的请求。
解决此问题最明显的方法是确保在拆除这些连接时负载均衡器是真实来源,确保负载均衡器的空闲超时小于应用程序服务器上的超时。根据其文档,此解决方案适用于 AWS 经典负载均衡器,但不适用于 ALB:
您可以为应用程序负载均衡器和传统负载均衡器设置空闲超时值。默认值为 60 秒。对于应用程序负载均衡器,空闲超时值仅适用于前端连接。
有人能推测为什么 AWS 可能删除了后端空闲超时(我假设它是无限的)?我也可以将节点服务器上的保持活动超时设置为无限,但我应该担心泄漏套接字吗?是否有任何其他服务器技术可以更优雅地处理此问题,我可以应用这些技术来修复此问题(不使用经典负载均衡器)?
AWS 支持还表示,他们不会尊重从服务发回的 Keep-Alive 标头。
答案1
我们无法知道他们没有这个功能的原因。我们无法知道导致这种行为的 AWS 设计/实施决策。只有与亚马逊合作开发此功能的人才知道,而且他们很可能签署了保密协议。
获得有效答案的唯一机会是询问 AWS。
答案2
相信 ALB 无限期地保持后端连接打开似乎不太合理,而是可配置超时仅适用于前端连接。
我有点担心从到达到离开和 ACK请求的时间为 :32.042,fd 关闭时间为 :32.066。您超时的连接可能实际上并非空闲——它提前 24 毫秒接受了请求。(!?) 对我来说,这是一段令人惊讶的“长”时间。
正如文档同一页所述,
传统负载均衡器使用预开放连接,但应用程序负载均衡器则不使用。
您不必担心泄漏描述符,因为 ALB 不会打开它实际上不需要用于处理请求的连接……但您也不需要无限超时。
问题似乎是 ALB 保持空闲后端连接打开多长时间——这似乎没有记录,但我会查看我的日志,看看我是否可以找到证据来表明计时器可能设置为多少,假设它是静态的。(保持后端连接打开当然是为了性能优化。)
直觉告诉我,您可以尝试使用 75 秒计时器。这些是我根据经典平衡器行为建立的默认设置,我发现将 ALB 替换为默认设置不会出现任何问题。