node.js - AppEngine nodejs 应用偶尔发送 502 并重启
问题描述
我们有一个成功部署到标准环境的 nodejs 应用程序。大约两个小时后(或更快,取决于流量)发生了一些事情:我们的下游客户端开始收到一堆 502 响应,然后服务稳定下来。我们认为这种情况至少已经发生了几个月。
在调查 502 的原因时,我看到:
- 没有未处理的异常/承诺拒绝日志表明节点应用程序已崩溃
- 我在接收时 console.log
SIGTERM
并且也没有出现在日志中 - nginx sidecar 的日志包括以下内容:
2020/06/16 23:11:11 [error] 35#35: *1149 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 169.254.1.1, server: _, request: "POST /api/redacted HTTP/1.1", upstream: "http://127.0.0.1:8081/api/redacted", host: "redacted.appspot.com""
我假设 502 来自 nginx,因为上游已经消失。我应该探索其他解释吗?
如果 GAE 有意替换我的应用程序容器,该过程不应该阻止这些类型的 502 吗?
SIGTERM
当应用程序/容器被替换时,我是否应该期望环境发送其他内容?
更新 #1 (2020-06-22)
我调查并发现证据表明我们可能超出了内存配额,因此我将 instance_class 从 F1 更改为 F2。在我写这篇文章时,我们的实例的内存使用量约为 200M(F2 有 512M 可用)。此外,我使用--max-old-space-size
开关将节点内存使用量设置为 496M。
502 仍在发生。
我怀疑 502 是由于自动缩放器终止实例而发生的。我们的应用永远不会收到SIGTERM
(即使在部署期间)。这意味着我无法优雅地关闭 http keepalive 连接,并且可以解释为什么 nginx 会引发对等连接重置。
更新 #2 (2020-06-24)
我们的服务只是标准的 REST 类型的东西,没有繁重的循环。
我将发布另一个带有一些内存图的更新,但我没有看到任何峰值。也许是一个小的内存泄漏。
这是我们的 app.yaml:
service: redacted
runtime: nodejs12
instance_class: F2
handlers:
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto
解决方案
我们在 App Engine Flexible 上部署的 Node.js 应用程序也遇到了非常相似的问题。
在我们的案例中,我们最终确定我们有内存压力导致 Node.js 垃圾收集器有时将请求处理延迟数百毫秒(有时更长)。这导致我们的健康检查 URL 偶尔超时,促使 GAE 从活动池中删除该实例。
因为我们通常只有两个实例来处理稳定的流量,删除一个实例很快就会使剩余的实例过载,它很快就会遭受同样的命运。
我们惊讶地发现,App Engine 可能需要两分钟或更长时间才能将流量分配给新创建的实例。在我们的原始实例被宣布不健康到新实例在线之间,502 将返回(可能是由 GAE 的 nginx)给客户端。
我们只需添加以下内容即可稳定环境:
automatic_scaling:
min_num_instances: 4
对我们的app.yaml
. 因为两个实例通常足以处理流量,所以确保我们始终运行四个显然使我们的内存使用率保持在足够低的水平,以防止 GC 停止请求处理,即使这样,我们也有足够的多余容量来处理一个被删除的实例。
GAE 标准的缩放设置略有不同。
回想起来,我们可以看到我们的延迟/响应时间在真正的问题开始之前会变得有点“紧张”。大多数响应的典型响应时间约为 30 毫秒,但我们会越来越多地看到 x00 毫秒范围内的异常请求。您可能需要检查您的请求日志以查看是否看到类似的内容。
New Relic 的Node.js VM 数据有助于检测垃圾收集所花费的时间越来越多。
推荐阅读
- c# - 在 .NET Core 2.2 中使用 xsltc.exe 生成程序集?
- python-3.x - 访问每个href链接后webscrape返回空字符串
- python - 我如何在熊猫中矢量化这个操作?
- python - Django CreateView 直观地指示必填字段,无需自定义模板
- batch-file - 如何在“for”命令中循环命令?
- node.js - Node.js 无法访问 Google AdSense 管理 API。'用户没有 AdSense 帐户'
- excel - 如何将工作表用作函数?
- google-apps-script - 不一致的错误消息“不允许操作(第 298 行,文件”
")" - ios - 在模拟器上运行,同时拥有在模拟器上不显示类的 SDK(阻止我运行)
- javascript - 如何将函数作为方法添加到返回的数组?