Node.js应用程序有周期性的缓慢和/或超时(不接受传入的请求)

Zan*_*aes 47 node.js

这个问题正在破坏我的生产服务器的稳定性.

回顾一下,基本思路是我的节点服务器有时会间歇性地减速,有时会导致网关超时.正如我从日志中可以看出的那样,有些东西阻塞了节点线程(意味着传入的请求不被接受),但我不能为我的生活找出什么.

问题的严重程度不等.有时应该<100ms的请求需要大约10秒才能完成; 有时它们甚至从未被节点服务器接受.简而言之,就好像一些随机任务正在工作并阻塞节点线程一段时间,从而减慢(甚至阻塞)传入请求; 我可以肯定的一点是,需要修复的症状是"网关超时".

问题来来去去,没有任何警告.我无法将其与CPU使用率,RAM使用率,正常运行时间或任何其他相关统计信息相关联.我已经看到服务器处理大的负载很好,然后在小负载下出现这个错误,所以它甚至看起来与负载无关.在太平洋标准时间凌晨1点左右看到错误并不罕见,这是当天最小的加载时间!重新启动节点应用似乎可能会让问题消失一段时间,但这真的不会告诉我太多.我确实想知道它是否可能是node.js中的一个错误 ...不是很令人欣慰,因为它正在杀死我的生产服务器.

  • 我做的第一件事是确保我已将node.js升级到最新版本(0.8.12),以及我的所有模块(这里都是).当然,我也有很多错误捕获器.我没有做任何时髦的事情,比如将许多内容打印到控制台或写入大量文件.
  • 起初,我认为是阻止传入套接字的出站HTTP请求,因为快速中间件甚至没有接收入站请求,但我放弃了理论,因为它看起来像节点线程本身变得忙碌.
  • 接下来,我使用JSHint完成了所有代码并修复了每一个警告,包括一些偶然的全局变量(忘记写"var")但这没有帮助
  • 在那之后,我假设也许我的内存耗尽了.但是,我通过nodetime的堆快照现在看起来非常好(如下所述).
  • 仍然认为记忆可能是一个问题,我看了一下垃圾收集.我启用了--nouse-idle-notification标志,并在不需要时对NULL对象进行了更多的代码优化.
  • 仍然确信内存是问题,我添加了--expose-gc标志并执行了gc(); 每分钟命令.这并没有改变任何东西,只是偶尔会让请求变慢一些.
  • 在绝望的尝试中,我设置了"群集"模块以使用2名工作人员并每30分钟自动重启一次.不过,没有运气.
  • 我将ulimit增加到10,000以上,并密切关注打开的文件.每个node.js应用程序似乎有<300个打开的文件(或套接字),因此增加ulimit没有任何影响.

我一直用nodetime记录我的服务器,这是它的主旨:

  • 在Amazon Cloud上运行的CentOS 5.2(m1.large实例)
  • 任何时候都可以提供超过5000 MB的可用内存
  • 堆栈大小始终小于150 MB
  • CPU使用率始终低于60%

我还检查了我的MongoDB服务器,其CPU使用率<5%且没有任何请求需要> 100ms完成,所以我非常怀疑是否存在瓶颈.

我已经使用Q-promises(几乎所有)代码使用Q-promises(参见代码示例),当然也避免了像瘟疫这样的Sync()调用.我试图在我的测试服务器(OSX)上复制这个问题,但运气不好.当然,这可能只是因为生产服务器被许多人以如此多的不可预测的方式使用,我无法通过压力测试来复制......

Zan*_*aes 11

在我第一次提出这个问题几个月后,我找到了答案.

简而言之,问题在于,当从一台服务器转移到另一台服务器时,我没有管道大资产.换句话说,我是在从一台服务器下载图像之后将其上传到S3存储桶.我没有将下载流式传输到上传中,而是将文件下载到内存中,然后上传.

我不确定为什么这不会出现在内存峰值或统计数据的其他地方.


Bil*_*ill 10

我的猜测是猫鼬.如果您在Mongo中存储大型有效负载,Mongoose可能会因为它构建Mongoose对象而变得非常慢.有关该问题的详细信息,请参阅https://github.com/LearnBoost/mongoose/issues/950.如果这是问题,你不会在Mongo本身看到它,因为查询很快返回,但是对象实例化可能需要75倍的查询时间.

尝试process.hrtime()在创建Mongoose对象之前和之后设置定时器(),以查看是否可能出现问题.如果这是问题,我将切换到直接使用节点Mongo驱动程序而不是通过Mongoose.

  • @ZaneClaes如果您使用的是Mongoose 3.x,可以在查询中调用[`lean()`](http://mongoosejs.com/docs/api.html#query_Query-lean)以消除大部分典型问题如果您只需要普通的JS对象而不是模型实例,那么开销很大 (2认同)