这个问题正在扼杀我的生产服务器的稳定性。
回顾一下,基本思想是我的节点服务器有时会间歇性变慢,有时会导致网关超时。尽我所能从我的日志中看出,有东西阻塞了节点线程(意味着传入的请求不被接受),但我一辈子都无法弄清楚是什么。
问题的严重程度不一。有时应该小于 100 毫秒的请求需要大约 10 秒才能完成;有时它们甚至根本不会被节点服务器接受。简而言之,就好像某个随机任务正在工作并阻塞节点线程一段时间,从而减慢(甚至阻塞)传入请求;我可以肯定地说的一件事是需要修复的症状是“网关超时”。
问题来来去去毫无预兆。我无法将它与 CPU 使用率、RAM 使用率、正常运行时间或任何其他相关统计数据相关联。我已经看到服务器可以很好地处理大负载,然后在小负载下出现此错误,因此它甚至看起来与负载无关。在太平洋标准时间凌晨 1 点左右看到错误并不罕见,这是一天中最小的加载时间!重新启动节点应用程序似乎可能会使问题消失一段时间,但这并不能告诉我太多。我确实想知道它是否可能是 node.js 中的一个错误……考虑到它正在杀死我的生产服务器,这不是很令人欣慰。
- 我做的第一件事是确保我已将 node.js 升级到最新版本(0.8.12),以及我的所有模块(在这里它们是)。当然,我也有很多错误捕捉器。我没有做任何时髦的事情,比如将很多内容打印到控制台或写入很多文件。
- 一开始我以为是出站的HTTP请求阻塞了入站的socket,因为express中间件连入站请求都没有接,但我放弃了这个理论,因为看起来节点线程本身变得很忙。
- 接下来,我用 JSHint 浏览了我的所有代码,并修复了每一个警告,包括一些意外的全局变量(忘记写“var”),但这并没有帮助
- 在那之后,我假设我可能内存不足。但是,我通过 nodetime 的堆快照现在看起来相当不错(如下所述)。
- 仍然认为内存可能是一个问题,我看了一下垃圾收集。我启用了 --nouse-idle-notification 标志,并在不需要时对 NULL 对象进行了更多代码优化。
- 仍然确信内存是问题所在,我添加了 --expose-gc 标志并执行了 gc(); 指挥每一分钟。这并没有改变任何东西,除了偶尔让请求变慢一点。
- 在绝望的尝试中,我将“集群”模块设置为使用 2 个工作人员并每 30 分钟自动重新启动一次。尽管如此,还是没有运气。
- 我将 ulimit 增加到 10,000 以上,并密切关注打开的文件。每个 node.js 应用程序似乎有 < 300 个打开的文件(或套接字),因此增加 ulimit 没有影响。
我一直在用 nodetime 记录我的服务器,这是它的要点:
- 在亚马逊云上运行的 CentOS 5.2(m1.large 实例)
- 始终大于 5000 MB 的可用内存
- 始终小于 150 MB 的堆大小
- CPU 使用率始终低于 60%
我还检查了我的 MongoDB 服务器,它的 CPU 使用率 <5%,并且没有请求需要 > 100 毫秒才能完成,所以我非常怀疑是否存在瓶颈。
I've wrapped (almost) all my code using Q-promises (see code sample), and of course have avoided Sync() calls like the plague. I've tried to replicate the issue on my testing server (OSX), but have had little luck. Of course, this may be just because the production servers are being used by so many people in so many unpredictable ways that I simply cannot replicate via stress tests...