【发布时间】:2014-11-03 21:41:10
【问题描述】:
我将以下 Node.js 代码编写为非常基本的 HTTP 服务器。它的目的是摄取大量包含 base64 数据的请求,并将该数据作为图像写入 S3。 S3 编写方面运行良好,没有任何问题。但是,初始请求在负载下似乎花费了异常长的时间。
server.js
http.createServer(function(req, res){
if (url.parse(req.url).pathname == '/processimage' && req.method.toLowerCase() == 'post') {
var startTime = new Date();
var rawBody = '';
req.on('data', function(chunk) {
rawBody += chunk;
});
req.on('end', function() {
console.log('REQUEST FINISHED: ' + (new Date() - startTime) + ' ms');
// Process image, upload to S3
res.writeHead(200);
res.end('data');
}
return;
} else {
// Other requests
}
}).listen(1347);
我也在计时图像处理部分,但它的表现很好,与这个问题无关。
为了对此进行测试,我编写了一个 POST 测试数据的脚本,其中包含大约 500k 个字符的 base64(2-3mb 原始图像)。在本地测试时,一切正常。我的输出是:
REQUEST FINISHED: 9ms
REQUEST FINISHED: 23ms
REQUEST FINISHED: 18ms
等等
但是,在 x-large 实例上将代码部署到 AWS 后,我看到以下内容:
REQUEST FINISHED: 499ms
REQUEST FINISHED: 2493ms
REQUEST FINISHED: 1784ms
REQUEST FINISHED: 3440ms
REQUEST FINISHED: 994ms
REQUEST FINISHED: 36043ms
基本上,在对此进行压力测试时,每 30 个请求中大约有 1 个请求似乎需要 10 多秒(在某些情况下甚至 30 多秒)才能通过请求管道。正如您在我的代码中看到的那样,在计算时间之前对数据进行了零处理,因此这意味着介于“req.on('data')”和“req.on('end')”之间,有很大的延迟。
我的问题是:在 req.on('data') 和 req.on('end') 之间是否发生某种处理会导致此 POST 花费这么长时间?主机是否可能由于某种原因(Ubuntu 12.04、x-large 实例、14GB 内存、4x CPU)阻塞了这些请求?
【问题讨论】:
-
如果您同时运行大量请求,那么您可能只是看到单个 node.js 线程同时处理多个请求,因此任何单个请求的总吞吐量时间都会延长只要有异步操作,它就会在每个请求之间切换。您没有显示 node.js 服务器实际上如何处理它接收到的数据,这可能与问题非常相关,因为这可能是一堆 CPU 的去向。
-
还请记住,数据不会一次全部到达。它以块的形式到达,每个块触发一个
req.on('data')回调。可能需要许多回调来提供 500k 块数据。如果您一次向服务器抛出大量请求,您的代码将同时“进行中”多个请求(每个请求都有自己的请求对象),您将从请求 A 中获得一个块,然后从请求 A 中获得一个块请求 B 等等。它不会先执行所有请求 A,然后执行请求 B。 -
@jfriend00 谢谢 - 我实际上已经删除了所有处理代码以缩小问题范围。完整的代码如下所示: req.on('end', function() { // console.log... res.writeHead(200); res.end('success'); } 你是正确的,块占用一段时间后,预计会有一些网络延迟。然而,当使用相同的 base64 代码重复请求时,时间范围从 300ms(可接受)到 36000(根本不)似乎很奇怪。
-
可能存在连接 base64 块的内存瓶颈。尝试
push将块放入req.on('data',...和.join()中的数组中req.on('end',...。通过简单地连接字符串,您要求垃圾收集器收集前一个字符串。在高负载下,这要么缩短了处理请求的时间,要么节点达到了 1.5gb 的内存限制
标签: node.js networking amazon-web-services