Nodejs 脚本中的性能问题这几天很困扰我
问题描述
假设:
- 这里有一个接口,在浏览器控制台中看到他的请求时间是 50ms
- 复制到同网络环境下的 postman 中调用,请求时间是将近 200ms ,请求头完全复制
- 把调用写到 js 脚本中,在同网络环境下 node 运行 ,console.time 显示也是 200ms
怀疑过程
- 一开始以为是 nodejs 瓶颈,在中文互联网下搜索原因寥寥无几,改去 stackoverflow 用 [nodejs is slower than chrome] 查找,有几篇类似的像这一篇,看回答基本都是是归咎于网络;
- 通过 fiddler 查看,有如下区别
- 在 js 脚本中把原本一次运行只调用一次的请求重复调用了几次,发现后几次速度逐渐接近浏览器原生访问
我的问题
- 我怀疑是不是有什么缓存机制在生效,与 fiddler 中的 TCP/IP Connect 和 ServerConnected 的差异相耦合,可惜到这里中文互联网上的资料就明显出现了欠缺,感觉我已经快找到正确的原因了,所以来找大家确认下
- 如果 1 是正确的,那对于每次运行都从头开始的 js 脚本,有什么解决方法吗? nginx 的缓存配置可以起到作用吗
Nodejs 脚本中的性能问题这几天很困扰我
keep alive 吧,chrome 多次请求就自动帮你处理了。nodejs 运行完脚本就停掉了所以打开的端口直接关了需要重开
听说 node.js 内置的 http 模块很拉, 在 node.js 里用 shell 去调用 CURL 发请求都比用内置的 http 模块快(听别人说的, 没实际验证过)
用 urllib 试试
觉得内置的 http 慢可以试试 uWebSockets.js
换成 deno 或者 bun 试试
进程开销,如果是 koa 常驻内存再试,应该可以稳定
- nodejs 环境启动开销
2. http 握手开销
你看过 nodejs 的架构图就知道了,nodejs 本身调用 http 请求最后也是用 nodejs 内置的 curl 库,c++和 js 的交互应该不算频繁,而且 V8 在跨语言交互这块不算差
- 浏览器的 keep-alive 机制优化掉了连接建立的开销
2. 浏览器默认会开启压缩,而 postman/node.js 默认没有压缩,如果 response body 较大,而且网速不够快的话,会有显著的区别
3. 如果你要测量一个接口的响应时间,最好在服务端测量,浏览器端的测量不可避免的会收到网络的影响
关于Node.js脚本中的性能问题,这里有几个常见的优化策略,希望能帮到你。
-
异步编程: Node.js是单线程的,但它是基于事件驱动的异步I/O模型。确保你使用异步函数(如
fs.promises
、axios
等)来避免阻塞事件循环。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();
-
事件循环监控: 使用
process.nextTick
和setImmediate
来优化事件循环的调度。process.nextTick(() => { console.log('nextTick'); }); setImmediate(() => { console.log('setImmediate'); });
-
内存管理: 及时释放不再使用的内存,避免内存泄漏。使用
WeakMap
和WeakSet
来存储可能变为垃圾回收对象的引用。 -
集群(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
等工具)来找出具体的瓶颈。