Nodejs 脚本中的性能问题这几天很困扰我

发布于 1周前 作者 bupafengyu 来自 nodejs/Nestjs

问题描述

假设:

  1. 这里有一个接口,在浏览器控制台中看到他的请求时间是 50ms
  2. 复制到同网络环境下的 postman 中调用,请求时间是将近 200ms ,请求头完全复制
  3. 把调用写到 js 脚本中,在同网络环境下 node 运行 ,console.time 显示也是 200ms

怀疑过程

  1. 一开始以为是 nodejs 瓶颈,在中文互联网下搜索原因寥寥无几,改去 stackoverflow 用 [nodejs is slower than chrome] 查找,有几篇类似的像这一篇,看回答基本都是是归咎于网络;
  2. 通过 fiddler 查看,有如下区别 在这里插入图片描述
  3. 在 js 脚本中把原本一次运行只调用一次的请求重复调用了几次,发现后几次速度逐渐接近浏览器原生访问 在这里插入图片描述

我的问题

  1. 我怀疑是不是有什么缓存机制在生效,与 fiddler 中的 TCP/IP Connect 和 ServerConnected 的差异相耦合,可惜到这里中文互联网上的资料就明显出现了欠缺,感觉我已经快找到正确的原因了,所以来找大家确认下
  2. 如果 1 是正确的,那对于每次运行都从头开始的 js 脚本,有什么解决方法吗? nginx 的缓存配置可以起到作用吗

Nodejs 脚本中的性能问题这几天很困扰我

12 回复

keep alive 吧,chrome 多次请求就自动帮你处理了。nodejs 运行完脚本就停掉了所以打开的端口直接关了需要重开


听说 node.js 内置的 http 模块很拉, 在 node.js 里用 shell 去调用 CURL 发请求都比用内置的 http 模块快(听别人说的, 没实际验证过)

用 urllib 试试

觉得内置的 http 慢可以试试 uWebSockets.js

换成 deno 或者 bun 试试

进程开销,如果是 koa 常驻内存再试,应该可以稳定

盲猜 tcp 连接延迟

有没有一种可能,浏览器的请求复用了一个 TCP 连接,你没发现你在 js 脚本里重复调用了几次只有第一次延迟有点高吗?

  1. nodejs 环境启动开销
    2. http 握手开销

你看过 nodejs 的架构图就知道了,nodejs 本身调用 http 请求最后也是用 nodejs 内置的 curl 库,c++和 js 的交互应该不算频繁,而且 V8 在跨语言交互这块不算差

  1. 浏览器的 keep-alive 机制优化掉了连接建立的开销
    2. 浏览器默认会开启压缩,而 postman/node.js 默认没有压缩,如果 response body 较大,而且网速不够快的话,会有显著的区别
    3. 如果你要测量一个接口的响应时间,最好在服务端测量,浏览器端的测量不可避免的会收到网络的影响

关于Node.js脚本中的性能问题,这里有几个常见的优化策略,希望能帮到你。

  1. 异步编程: Node.js是单线程的,但它是基于事件驱动的异步I/O模型。确保你使用异步函数(如fs.promisesaxios等)来避免阻塞事件循环。

    const fs = require('fs').promises;
    
    async function readFile() {
        try {
            const data = await fs.readFile('example.txt', 'utf8');
            console.log(data);
        } catch (err) {
            console.error(err);
        }
    }
    
    readFile();
    
  2. 事件循环监控: 使用process.nextTicksetImmediate来优化事件循环的调度。

    process.nextTick(() => {
        console.log('nextTick');
    });
    
    setImmediate(() => {
        console.log('setImmediate');
    });
    
  3. 内存管理: 及时释放不再使用的内存,避免内存泄漏。使用WeakMapWeakSet来存储可能变为垃圾回收对象的引用。

  4. 集群(Cluster): 利用Node.js的集群模块来创建多个工作进程,充分利用多核CPU。

    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;
    
    if (cluster.isMaster) {
        for (let i = 0; i < numCPUs; i++) {
            cluster.fork();
        }
    } else {
        http.createServer((req, res) => {
            res.writeHead(200);
            res.end('hello world\n');
        }).listen(8000);
    }
    

这些策略可以显著提升Node.js应用的性能。如果问题依然存在,建议进行性能分析(如使用clinic.js等工具)来找出具体的瓶颈。

回到顶部