【问题标题】:NodeJS HTTP server stalled on V8 executionNodeJS HTTP 服务器在 V8 执行时停止
【发布时间】:2014-05-24 06:36:48
【问题描述】:

已编辑

我有一个 nodeJS http 服务器,用于接收来自多个客户端的上传并分别处理它们。 我的问题是我已经验证了第一个请求会阻止任何其他请求的接收,直到前一个请求得到处理。

这是我测试过的代码:

var http = require('http');
http.globalAgent.maxSockets = 200;
var url = require('url');
var instance = require('./build/Release/ret');

http.createServer( function(req, res){
    var path = url.parse(req.url).pathname; 
    console.log("<req>"+path+"</req>");
    switch (path){
        case ('/test'): 
            var body = [];
            req.on('data', function (chunk) {
                body.push(chunk);
            });
            req.on('end', function () {
                body = Buffer.concat(body);
                console.log("---req received---");
                console.log(Date.now());
                console.log("------------------");          
                instance.get(function(result){
                  postHTTP(result, res);
                });
            });
        break;
    }
}).listen(9999);

这是本地端(省略明显的东西),其中 getInfo 是导出的方法:

std::string ret2 (){
  sleep(1); 
  return string("{\"image\":\"1.JPG\"}");
}

Handle<Value> getInfo(const Arguments &args) {
  HandleScope scope;
  if(args.Length() == 0 || !args[0]->IsFunction())
    return ThrowException(Exception::Error(String::New("Error")));

  Persistent<Function> fn = Persistent<Function>::New(Handle<Function>::Cast(args[0]));

  Local<Value> objRet[1] = {    
    String::New(ret2().c_str())
  };
  Handle<Value> ret = fn->Call(Context::GetCurrent()->Global(), 1, objRet);

  return scope.Close(Undefined());

}

我用 3 个 curl 并行请求来解决这个问题

for i in {1..3}; do time curl --request POST --data-binary "@/home/user/Pictures/129762.jpg" http://192.160.0.1:9999/test & done

这是服务器的输出:

<req>/test</req>
---req received---
1397569891165
------------------
<req>/test</req>
---req received---
1397569892175
------------------
<req>/test</req>
---req received---
1397569893181
------------------

这些来自客户端的响应和时间:

"1.JPG"
real    0m1.024s
user    0m0.004s
sys         0m0.009s
"1.JPG"
real    0m2.033s
user    0m0.000s
sys         0m0.012s
"1.JPG"
real    0m3.036s
user    0m0.013s
sys         0m0.001s

显然请求是在前一个服务完成后收到的。 sleep(1) 模拟一个需要大约 1 秒才能完成且无法更改的同步操作。 客户端以约 1 秒的增量延迟接收响应。

我想实现一种并行性,尽管我知道我处于单线程环境中,例如 nodeJS。我想要实现的是收到所有 3 个答案是 ~1s。

提前感谢您的帮助。

【问题讨论】:

    标签: javascript node.js http asynchronous v8


    【解决方案1】:

    这个:

    for(var i=0;i<1000000000;i++) var a=a+i;
    

    是一个相当严重的阻塞操作。一旦第一个区块结束。你的整个服务器挂起,直到这个 for 循环完成。我对你为什么要这样做很感兴趣。

    也许您正在尝试模拟延迟响应?

    setTimeout(function)({
        send404(res);
    }, 3000);
    

    现在,您正在通过附加data 事件处理程序将非流动流转换为流动模式,然后将整个流加载到内存中。你可能不想这样做。

    您可以在如下图所示的 now-flowing 模式下使用流,如果您想将数据发送到仅在其他事件之后才能访问的某个地方,这将非常有用。

    但是,在流动模式下使用流是最快的。如果您想编写自己的正文解析器,我想您可能想使用流动模式,这取决于您的用例。

    req.on('readable', function () {
       var chunk;
       while (null !== (chunk = readable.read())) {
           body.push(chunk);
       }
    });
    

    流动和非流动模式也分别称为 v1 和 v2 流,因为节点中使用的旧流仅支持流动模式。

    【讨论】:

    • 我试过设置超时,但正如你所说,这是一个非阻塞操作。在我的实际部署中,我有一个阻塞操作,所以我认为这是模拟它的好方法。我不确定在这种情况下如何收听可读的流事件。
    • 我会建议您更改您的实际部署以删除该阻塞操作,任何阻塞操作对于 node.js 性能来说都接近于致命。
    • 真实部署中的阻塞操作是什么? nodejs中的大多数事情都是在后台进行阻塞操作,即使它是一个c模块,你也可以在一个线程中做事情,然后在操作完成时调用回调。你不应该使用 fs.[read|write]sync 调用,总是使用异步调用。
    • 不能使用线程,因为并非我链接到节点 C 扩展的所有库都是线程安全的。我将尝试使用 node-ffi 看看它是否有任何不同。想不出别的了。
    • 如果对时间不敏感,您可以将阻塞操作的计算传播到事件循环中。如果您愿意分享您的用例,我们可能会给您一些更可靠的反馈。
    猜你喜欢
    • 1970-01-01
    • 2021-03-02
    • 2013-07-03
    • 1970-01-01
    • 2019-10-27
    • 2017-11-28
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    相关资源
    最近更新 更多