14

编辑

经过一番折腾,我终于找到了一些看起来可能是可靠的线索:

当 express 库当前正在使用 Node+OAuth 模块执行多个出站请求(例如,到 Facebook、Twitter 等)时,它无法接受传入请求。我可以通过在我的代码中放置大量日志来确定这一点,我发现在出站请求中间时没有触发“开始请求”日志(如下所述)。

我已经能够证明,当 Node+OAuth 模块发出一些出站请求时,对我的 API 的入站请求(通过浏览器窗口)将挂起并且在其中一个出站 OAuth 请求完成之前不会被接收。

当然,我已经做了:

require('http').globalAgent.maxSockets = 999;

根据 IRC 中的建议,我添加了

console.log(require('http').globalAgent.requests);

但这似乎总是 === {},这意味着没有挂起的入站请求 AFAIK。

因此,我只能得出结论,由于出站请求,node.js 或 express 选择阻止传入请求,即使应该有足够的套接字可用......

有人对如何解决这个问题有任何提示吗?


我有一个使用 Express、Mongoose 等在 node.js 中创建的 API,部署在 Amazon Cloud 上,它在 99% 的时间里运行良好且快速。

除了偶尔,请求似乎以某种方式被丢弃或以其他方式忽略。我说的是通常在几毫秒内完成的请求,随机无响应,没有清楚的原因

症状是连接到 API 端点时出现简单的“网关超时”。一个相同的请求,从同一个客户端发出的具有相同参数的,就在之前或之后,都可以正常工作。

当然,我的第一个想法是“呃,服务器过载!” 所以我花了很多时间优化我的请求、monogoDB 等。最后我发现 CPU/磁盘/RAM 的整体使用率(在 Node.js 服务器和 Mongo 服务器中)非常低。我使用 Scout 和 RightScale 实时跟踪我的服务器,并记录任何超过 100 毫秒的请求或查询。我的节点服务器目前有 5GB 的可用 RAM、70% 的可用 CPU(在第一个核心上)等。所以我 99.99% 确定这不是性能问题。

最后,我放弃了绝望的尝试:我为我的客户提出的所有请求附加了一个随机数。然后,在 node.js 应用程序中,我在第一次收到请求并完成时执行 console.log()。例如,这是我在 express 中使用的中间件:

var configureAPI = function() {
    return function(req, res, next) {
        if(req.body.ruid)
            console.log(req.body.ruid);

        // more middleware stuff...
    };
}
server.configure(function(){

    server.use(express.bodyParser());
    server.use(configureAPI());
    server.use(onError);

    // ...  more config stuff
}

我的发现让我震惊:显然,node.js 应用程序甚至没有收到有问题的请求。我有一个 Javascript webapp,我打印了随请求发送到控制台的“ruid”。每当请求成功时,都会在 node.js 控制台中打印出相应的“ruid”。每当它超时,就没有。


编辑:更多调试和信息。

我的应用服务器实际上开始(并继续)也为 PHP 提供服务(因此,它们安装了 Apache 等)。我需要http://streamified.me来服务我的网站(PHP)和http://api.streamified.me来服务我的 API(node.js)......所以我的 httpd.conf 文件中有一行导致对 api.streamified.me(而不是 streamified.me)的请求通过端口 8888 转到 node.js:

RewriteCond %{HTTP_HOST} ^api.streamified.me
RewriteRule ^(.*) http://localhost:8888$1 [P]

因此,在同一个 httpd.conf 文件中,我打开了 RewriteLogLevel 5,然后在我的本地主机上创建了一个简单的 PHP+CURL 脚本,以使用随机 URL 访问我的 api.streamified.me(这应该会导致 node.js 触发一个简单的“未找到”响应),直到导致网关超时。在这里,您可以看到它已经发生了——并且重写日志显示该请求肯定被应用服务器接收并转发到端口 8888 ......但它从未被 node.js 接收(或者,至少,中间件第一行中的第一行代码永远不会得到它......)

在此处输入图像描述


我一遍又一遍地检查了我的 node.js 代码,并且很确定我没有阻塞代码,即使我这样做了,我也无法想象它阻塞线程足够长的时间以致错过一个请求,而不会在某处引发红旗。

我错过了什么?传入的套接字是否会被阻塞?我确实通过我的 node.js 应用程序向外部 API 发出了相当数量的 HTTP 请求,但 AFAIK 不应该阻塞传入的套接字。


当然,我有错误日志记录。我已在进程级别启用它...

process.addListener("uncaughtException", function (err) {
    // some logging code
}

在 Express 级别(上面的 onError 处理程序)。我知道我的错误记录功能可以工作,因为我以前见过它们都触发过。但是他们都没有在请求被丢弃的时候报告任何东西,我也没有在控制台中看到任何东西......


  • 快捷版:3.0.0rc5
  • Node.js 版本:0.8.12
  • 在标准 Amazon Cloud 设置(m1.large 实例)上运行的 2 个 node.js 应用程序实例,位于 2 个负载均衡器后面,连接到 3 个 MongoDB 副本集(也是 m1.large)
4

1 回答 1

2

听起来您将 Node 线程锁定太久,导致传入连接在处理它们之前超时。Node 是单线程的,所以它一次只做一件事,它不能选择阻止传入请求,因为传出请求。它只能因为忙于做其他事情而无法接受传入的请求。你需要弄清楚它在忙什么。

如果您不发出出站请求,一切正常吗?如果是这样,您需要查看发出这些请求的代码,以确保您没有等待响应。

于 2012-10-13T19:48:51.213 回答