1

在我的节点站点中,我调用了一个使用标准 http get 构建的 RESTful API 服务。在成功进行了几个小时的通信后,我发现请求停止发送,它只是等待并最终超时。

被调用的 API 仍然可以很好地接收来自其他地方的请求,但是当从站点发送请求时,它不会到达 API。

我尝试过使用 stream.pipe、util.pump 并将文件写入文件系统。

我正在使用节点 0.6.15。我的站点和被调用的服务位于同一台服务器上,因此正在调用 localhost。内存使用率约为 25%,cpu 平均使用率约为 10%。

经过一段时间的问题,我开始使用请求模块,但我得到了相同的行为。它在失败之前发出的调用次数似乎在 5 到 100 之间。最后我必须重新启动站点,而不是重新启动 api 才能使其再次工作。

网站中的代码大致如下所示:

var Request = require('request');
downloadPDF: function(req, res) {
  Project.findById(req.params.Project_id, function(err, project) {
    project.findDoc(req.params.doc_id ,function(err, doc) {
      var pdfileName;
      pdfileName = doc.name + ".pdf";
      res.contentType(pdfileName);
      res.header('Content-Disposition', "filename=" + pdfileName);
      Request("http://localhost:3001/" + project._id).pipe(res);
    });
  });
}

我很了解可能发生的事情。

4

5 回答 5

4

我不确定您的 Node 服务器有多忙,但可能是您的所有套接字都处于 TIME_WAIT 状态。

如果您运行此命令,您应该会看到有多少个套接字处于此状态:

netstat -an | awk '/tcp/ {print $6}' | sort | uniq -c

当然,有一些是正常的。您只是不想最大化系统的可用套接字并让它们都在 TIME_WAIT 中。

如果是这种情况,您实际上希望减少agent.maxSockets 设置(与@user1372624 的建议相反),否则每个请求都只会收到一个新的套接字,即使它可以简单地重用最近的套接字。达到无响应状态只需要更长的时间。

我发现这个Gist(http.Agent 的一个补丁)可能会对你有所帮助。

此服务器故障答案也可能有所帮助:https ://serverfault.com/a/212127

最后,更新 Node 也可能会有所帮助,因为他们可能已经解决了自您的版本以来的保活行为(您可以查看更改日志)。

于 2012-06-07T23:29:39.563 回答
4

您是否尝试增加 agent.maxSockets 或禁用 http.Agent 功能?默认情况下,最近的节点版本使用套接字池进行 HTTP 客户端连接,这可能是问题的根源 http://nodejs.org/api/http.html#http_class_http_agent

于 2012-06-03T17:43:28.630 回答
0

您正在使用回调返回一个没有多大意义的值,因为您的 Project.findById() 立即返回,而无需等待提供的回调完成。

不过不要感觉不好,nodejs 使用的编程模型一开始有点难以理解。

在事件驱动编程 (EDP) 中,我们提供回调来完成结果,忽略它们的返回值,因为我们永远不知道何时实际调用回调。

这是一个简单的例子。

假设我们要将 HTTP 请求的结果写入文件。

在过程式(非 EDP)编程环境中,我们依赖仅在有返回值时才返回值的函数。

所以我们可能会写一些类似(伪代码)的东西:

    url = 'http://www.example.com'

    filepath = './example.txt'

    content = getContentFromURL(url)

    writeToFile(filepath,content)

    print "Done!"

它假设我们的程序将等待直到 getContentFromURL() 联系远程服务器,发出请求,等待结果并将结果返回给程序。

writeToFile() 函数然后要求操作系统在某个文件路径上打开一个本地文件以进行写入,等待直到它被告知打开文件操作已完成(通常等待磁盘驱动程序报告它可以执行这样的操作。 )

writeToFile() 然后请求操作系统将内容写入新打开的文件,等待直到被告知操作系统用于写入文件的驱动程序告诉它它已经完成了这个目标,将结果返回给程序以便它可以告诉我们程序已经完成。

创建 nodejs 要解决的问题是更好地利用上面发生的所有等待所浪费的所有时间。

它通过使用函数(回调)来实现这一点,这些函数在诸如从远程 Web 请求检索结果或将文件写入文件系统等操作完成时调用。

为了在事件驱动的编程环境中完成上述相同的任务,我们需要编写相同的程序:

    getContentFromURL(url,onGetContentFromURLComplete)

    function onGetContentFromURLComplete(content,err){
        writeToFile(content,onWriteToFileComplete);
    }

    function onWriteToFileComplete(err){
        print "Done!";
    }

在哪里

  • 调用 getContentFromURL() 仅在获得 Web 请求的结果后调用 onGetContentFromURLComplete 回调,并且
  • 调用 writeToFile() 仅在成功完成写入内容时调用其回调以显示成功消息。

nodejs 的真正魔力在于,它可以在程序函数必须等待大多数时间密集型操作(例如与输入和输出相关的操作)完成的惊人大量时间中完成各种其他事情。

(上面的例子忽略了所有通常被认为是坏事的错误。)

于 2012-04-20T22:44:45.193 回答
0

您是否在调用此函数时尝试记录您的参数?错误可能取决于 req.params.Project_id。您还应该在回调函数中提供错误处理。

如果您可以确定对某个参数集的失败请求(使它们可重现),您可以使用节点检查器轻松调试您的应用程序。

于 2012-06-06T07:50:40.407 回答
0

使用内置函数时,我也遇到过间歇性错误。作为一种解决方法,我使用本机 wget。我做类似以下的事情

var exec = require('child_process').exec;
function fetchURL(url, callback) {
    var child;
    var command = 'wget -q -O - ' + url;
    child = exec(command, function (error, stdout, stderr) {
            callback(error, stdout, stderr);
        });
}

通过一些小的调整,您可以使其满足您的需求。到目前为止,它对我来说是坚如磐石。

于 2012-04-21T04:30:14.123 回答