使用Node.js + Express 2代理大量的HTTP请求

5
我正在使用Node.js + Express 2编写代理。代理应该:
  1. 解密POST有效载荷,并根据结果向服务器发出HTTP请求;
  2. 加密来自服务器的回复并将其发送回客户端。
与加密相关的部分运行良好。我面临的问题是超时。代理应在15秒内处理请求。实际上,大多数请求都在500毫秒以下完成。
当我增加并行请求的数量时,问题就出现了。大多数请求都完成得很好,但某些请求在15秒后失败了几毫秒。使用并发500和ab -n5000 -c300可以正常工作,但有些请求由于超时而失败。
我只能推测,但问题似乎是回调执行顺序的问题。是否可能先到达的请求一直挂起,直到因为节点专注于最新的请求而在500ms内及时处理仍在进行中的请求导致ETIMEDOUT
P.S.:远程服务器没有问题。我正在使用request与其交互。 更新 使用一些代码的方式:
function queryRemote(req, res) {
  var options = {};  // built based on req object (URI, body, authorization, etc.)
  request(options, function(err, httpResponse, body) {
    return err ? send500(req, res)
               : res.end(encrypt(body));
  });
}

app.use(myBodyParser);  // reads hex string in payload
                        // and calls next() on 'end' event

app.post('/', [checkHeaders,   // check Content-Type and Authorization headers
               authUser,       // query DB and call next()
               parseRequest],  // decrypt payload, parse JSON, call next()
         function(req, res) {
  req.socket.setTimeout(TIMEOUT);
  queryRemote(req, res);
});

我的问题是:当ab发送20个POST请求到/时,Express路由处理程序会被调用数千次。这并不总是发生,有时只有20个请求会及时处理。
当然,ab不是问题。我可以百分之百确定只有ab发送了20个请求。但是路由处理程序被多次调用。
我找不到这种行为的原因,有什么建议吗?

你能分享一些代码吗?处理事务的方式是怎样的? - Farid Nouri Neshat
2个回答

2
超时是由于使用了http.globalAgent引起的,默认情况下它可以处理高达5个并发请求到一个host:port(在我的情况下这是不够的)。 ab发送了数千个请求(而不是几十个)(在OS X下经过Wireshark批准的事实;我无法在Parallels内部的Ubuntu中重现此问题)。

1

您可以查看node-http-proxy模块以及它如何处理连接。确保不要缓冲任何数据,并且一切都通过流式传输进行处理。您应该尝试查看长请求花费的时间在哪里。尝试使用conosle.timeconsole.timeEnd来检测代码的部分,看看哪里花费了最多的时间。如果大部分时间都花费在JavaScript上,您应该尝试对其进行分析。基本上,您可以使用v8分析器,通过将--prof选项添加到您的节点命令中。这会生成一个v8.log文件,可以通过位于node-source-dir/deps/v8/tools的v8工具进行处理。只有在通过scons(scons d8)安装d8 shell的情况下才能正常工作。您可以查看this article以帮助您进一步使其正常工作。

您还可以使用node-webkit-agent,它使用WebKit开发工具来显示分析器结果。您也可以看一下我的分支,稍微加了点糖。

如果那不起作用,您可以尝试dtrace分析(仅适用于基于illumos的系统,如SmartOS)。


我应该读取负载,解密它,并将其进一步发送到远程服务器。然后,我读取远程的回复,加密它并发送回来。大部分时间是与远程进行IO交互。但我面临的问题是:假设ab发送了20个请求,但表达式调用路由回调的次数太多了(比如一千多次)。对此有什么建议吗? - Aleksei Zabrodskii
这看起来不对。也许在中间件中多次调用了回调函数(next)。请检查所有中间件。另外,根据你的代码,你应该使用流式传输(与现在相反),但是你不能像这样使用express中间件。 - Farid Nouri Neshat
首先,我无法进行流式传输。我需要整个主体进行解密,整个远程响应进行加密。我的意思是,是的,我可以将十六进制串流转换为密码,然后从那里将解密的主体发送到远程服务器再返回,但这太麻烦了(而且授权实现起来也很棘手)。所以我坚持当前的方法。其次,我怎样才能使用express中间件? - Aleksei Zabrodskii
Express 不是专为流式传输而构建的,但没关系。我现在可以理解你的痛苦了。还有一件事我忘了提醒,可能是垃圾收集器暂停导致应用程序变慢。您可以添加 --trace_gc 选项,查看每个垃圾回收需要多长时间。 - Farid Nouri Neshat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接