我有一个相当简单的 AWS Elastic Beanstalk 设置(Rails on Puma,带有 NGINX),客户端会间歇性地出现但相当频繁的 504 网关超时(通常在发出请求后 10 秒)。失败的请求非常简单,因此不应该超时。
NGINX 充当在同一实例上运行的 Puma 应用服务器的反向代理,并提供 TLS 终止。此设置中有两个 Beanstalk 管理的 EC2 实例,位于标准 Beanstalk 配置的 AWS 应用程序负载均衡器 (ALB) 后面。负载均衡器还会在将 TLS 连接传递给 NGINX 之前终止它。
browser (443) ---> (443) ALB (443) ---> | (443) NGINX (socket)-> Puma |
我已按照 AWS 故障排除步骤进行操作:https://aws.amazon.com/premiumsupport/knowledge-center/504-error-alb/
所有这些实际上证实了监控显示 HTTPCode_ELB_5XX 计数,这表明 504 错误源自负载均衡器。NGINX 没有返回 50x 错误。我检查了 ALB 日志,它们显示发生了 504 错误,但与任何特定目标无关。请求从未到达目标后端。监控做显示目标连接错误。
我有一个特定的 NGINX 服务器配置,其中唯一真正相关的设置(在server {...}
块内)是:
ssl_session_timeout 5m;
client_max_body_size 20M;
proxy_read_timeout 300;
client_header_timeout 75;
client_body_timeout 75;
keepalive_timeout 75;
ALB 配置具有空闲超时 60 秒
EC2 显示内存利用率仅约为 50%,且 CPU 较低。
我还花了一些时间研究:https://sigopt.com/blog/the-case-of-the-mysterious-aws-elb-504-errors/这让我开始研究 keepalives 等以及 Wireshark。总之,NGINX 显示客户端 ALB 关闭了连接。不久之后,有时我会在浏览器中收到 504。这通常是 10 秒后,对应于 ALB 无法从目标获得返回。但没有理由目标不应该响应,它们甚至没有被触及。这几乎就像一个安全组问题,只是偶尔会阻止请求,但这些要么有效,要么无效。
当这些错误发生时,应用服务器已经预热,并且当故障发生时不会出现 CPU 峰值。
我知道该应用程序在没有 ALB 的单实例 beanstalk 上运行良好,所以我们可以排除本次讨论中的应用程序性能。
任何帮助或建议都将非常感激。
答案1
我认为这是因为 Puma 在最初启动时完全拒绝连接。预热可能会使情况变得更糟,因为启动所有线程的时间可能会减慢资源受限服务器上的初始启动速度。
如果将development.rb
条目更改为:您可以在开发中更清楚地看到这一点:
config.cache_classes = true
config.eager_load = true
这使得它在加载方面更接近生产模式。启动 rails 服务器并立即转到 http://localhost:3000
如果你检查浏览器开发者控制台中的网络请求,你会看到一个net::ERR_CONNECTION_REFUSED
状态,直到 Puma 说它正在监听
* Listening on http://127.0.0.1:3001
* Listening on http://[::1]:3001
Use Ctrl-C to stop
对于我的应用程序,它在初始启动时会进行大量动态加载和类创建,这需要超过 10 秒的时间。因此,在此期间对 NGINX 的任何请求都会立即失败,因为 Puma 没有监听。将来可能创建新工作线程的请求可能会很慢,但不会失败,因为 Puma 已经在监听并接受连接。
这并不能解决问题,但至少可以帮助我停止追逐干扰因素。现在我需要弄清楚是否有办法让 Puma 更快地开始监听,或者让 NGINX 以某种方式等待 Puma 接受连接,然后再告诉客户端存在问题,然后破坏负载均衡器。