NodeJS快速服务器在长时间空闲后对第一个请求的响应非常慢



我有一个简单的nodejs express服务器,我遇到了一个问题,长时间空闲后的第一个请求非常慢。3-4分钟。相同或类似的请求第二次和第三次需要几毫秒。

我看了看这个页面- https://expressjs.com/en/advanced/best-practice-performance.html,并做了以下事情-

  1. 使用gzip压缩
  2. 设置NODE_ENV为production

但是我仍然遇到第一个请求非常慢的问题。

服务器正在执行以下操作-

  1. 在启动时,我从一个包含字符串列表的大文本文件中读取。这些字符串中的每一个都被添加到数组中。数组的大小通常在350万项左右。

  2. 用户提供一个字符串输入,我循环遍历数组中的所有条目,使用indexOf搜索匹配项并返回匹配项。

我还尝试将服务器的内存——max-old-space-size从4096增加到8192,但这没有帮助。我是使用nodejs/express的新手,如果还有什么我需要考虑/调查的,请告诉我。

谢谢。

来源-

var compression = require('compression')
const express = require('express')
var cors = require('cors')
var bodyParser = require('body-parser')
const fs = require('fs') 
// Get command line arguments
const datafile = process.argv[2];
const port = Number(process.argv[3]);
if(process.env.NODE_ENV === 'production') {
console.log("Starting in production mode");
}
// Init
const app = express()
app.use(cors());
app.use(bodyParser.text());
app.use(compression());
app.post('/', (request, response) => {
var query = JSON.parse(request.body).query;
var results = SearchData(query);
response.send(results);
})
// Init server
app.listen(port, (err) => {
if (err) {
return console.log('Something bad happened', err)
}
console.log(`server is listening on port ${port}`)
})
console.log('Caching Data');
var data = fs.readFileSync('/datafile.txt', 'utf8');
var datalist = data.toString().split('n');
var loc = [];
for (var i = 0; i < datalist.length; i++) {
const element = datalist[i];
const dataRaw = element.split(',');
const dataStr = dataRaw[0];
const dataloc = processData(dataRaw[1]); 
datalist[i] = dataStr;
loc.push(dataloc);
}
console.log('Cached ' + datalist.length + ' entries');
function SearchData (query) {
const resultsLimit = 32;
var resultsCount = 0;
var results = [];
for (var i = 0; i < datalist.length; i++) {
if (datalist[i].indexOf(query) === -1) {
contiue;
}
results.push(datalist[i] + loc[i]);
resultsCount++;
if (resultsCount == resultsLimit) break;
}
return results;
}

使用——trace-gc标志后的更多细节。

启动流程&等待直到所有字符串都加载到内存中。

在下午5点48分,一个带有特定查询字符串的请求花费了大约520毫秒。

相同的请求在8:11 PM大约157975毫秒。

在启动过程中,我看到了很多这样的消息-

[257989:0x3816030] 33399 ms: Scavenge 1923.7 (1956.9) -> 1921.7 (1970.9) MB, 34.2 / 0.0 ms (average mu = 0.952, current mu = 0.913) allocation failure

来自gc日志的最后一条消息显示如下-

[257989:0x3816030] 60420 ms: Mark-sweep 1927.9 (1944.9) -> 1927.1 (1939.1) MB, 164.0 / 0.0 ms (+ 645.6 ms in 81 steps since start of marking, biggest step 123.0 ms, walltime since start of marking 995 ms) (average mu = 0.930, current mu = 0.493) finalize incremental marking via task GC in old space requested

当响应非常缓慢时,我没有看到gc的任何其他内容。如果有人能从这些日志中推断出什么,请告诉我。

这些是nodejs和express服务器版本-

  1. node——version ->12.20.0
  2. express——version ->4.16.4

服务器似乎进入睡眠状态,需要很长时间才能唤醒。

我能够使用基于Rust的实现找到这个问题的解决方案,但是这种行为的根本原因不是nodejs/express服务器,而是我部署这些代码的机器。

首先,我使用actix-web框架迁移到基于Rust的实现,并注意到使用nodejs/express时遇到的类似性能问题。

然后我使用Rust rayon库并行处理大型数组,这解决了我所看到的性能问题。

我认为问题的根本原因是我部署这段代码的服务器有一个较小的处理器,我没有在我的开发机器上遇到这个问题,因为它有一个更好的处理器-

服务器机器- Intel Core Processor2100MHz8核16线程

Dev machine - Intel Xeon Processor3.50GHz6 core 12 Threads

可能使用任何并行处理库与nodejs/express实现也会解决这个问题。

最新更新