Node.js 应用无法高效处理并发请求。

4
我正在管理一个运行nodejs (next.js)应用程序的服务器,目前我将其视为一个黑盒子。我使用pm2以fork模式运行该应用程序,使用ecosystem.config.js配置文件。
module.exports = {
  apps: [
    {
      name: "app-frontend-nextjs",
      cwd: "/home/user/app/frontend-nextjs",
      script: "npm",
      args: "start",
      env: {}
    }
  ]
};

运行pm2 list的结果如下:
┌─────┬────────────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name                   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼────────────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 1   │ app-frontend-nextjs    │ default     │ N/A     │ fork    │ 2413063  │ 27D    │ 5    │ online    │ 0%       │ 64.6mb   │ xxxxxx   │ disabled │
└─────┴────────────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 2.3% | mem free: 62.0% | ens3: ⇓ 0mb/s ⇑ 0mb/s | disk: ⇓ 0mb/s ⇑ 0mb/s /dev/mapper/ubuntu--vg-ubuntu--lv 67.4% |


应用程序用于响应HTTP请求,并通过执行一些(或许很多)API调用来组装这些响应,这些API调用是对本地安装的Drupal网站进行的。Drupal网站对单个或并发请求的响应非常快,不是问题的一部分。
应用程序通常需要约7.5秒来生成响应。
$ curl -s -w 'seconds %{time_total}\n' -I 127.0.0.1:3000 | grep seconds
seconds 7.568871

这个很慢,但并不是问题的根本原因。
如果我同时发出3个请求,通常第一个请求会在大约7.5秒内完成,而其他两个请求会在大约22秒内完成。
$ curl -s -w 'seconds %{time_total}\n' -I 127.0.0.1:3000 | grep seconds &
[1] 482148
$ curl -s -w 'seconds %{time_total}\n' -I 127.0.0.1:3000 | grep seconds &
[2] 482150
$ curl -s -w 'seconds %{time_total}\n' -I 127.0.0.1:3000 | grep seconds &
[3] 482152
$
$ seconds 7.809088
seconds 22.355956
seconds 22.355522

请注意,3乘以7.5等于22.5,所以有些请求似乎会等待其他请求全部完成。
我执行了6个请求的测试,响应时间如下:
seconds 7.580153
seconds 14.922243
seconds 43.844184
seconds 43.841478
seconds 43.844960
seconds 43.848788

这证实了一些响应等待其他响应完成。

大多数并行响应在完全相同的时间内完成(毫秒级别),这很可疑,表明有一些奇怪的事情正在发生。某些东西阻止了这些响应的派发,直到它们全部完成处理。

为什么应用程序会表现出这种行为?是因为我在“fork”模式下运行应用程序,还是应该开始查看应用程序的代码,以确定是否存在某些神秘的锁定逻辑导致了这种行为?


我几乎可以保证,事件循环被阻塞,原因是有一个耗时的任务没有被异步执行。我曾见过有人因为这样的问题被解雇,尽管已经多次向他展示了如何编写非阻塞代码。如果没有看到与这些请求相关的代码,调试将会很困难,但可以从查看输入/输出、文件读取、循环等方面入手。任何看起来需要一定时间完成的操作都值得关注。 - undefined
你确定要以生产模式启动它吗?还要检查一下数据库,看连接是否正确完成。 - undefined
1个回答

0
Node代码可以同步运行(按顺序执行,直到完成才继续)和异步运行(立即执行,不关心是否完成)。
这种行为表明你的应用程序逻辑中可能存在一些前者的情况。确认这一点的一个好方法是检查Drupal网站的日志,看看你的应用程序是如何访问它的。
如果日志显示在相同时间段有类似的使用和延迟,你需要验证你的应用程序代码是否尽可能地异步运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接