Node.js服务器超时问题(EC2 + Express + PM2)

我相对较新的运行生产node.js应用程序,我最近有问题,我的服务器超时。

基本上在一定的使用和时间后,我的node.js应用程序停止响应请求。 我甚至不再看到路由器在我的控制台上被触发 – 就像整个事情刚刚停止,来自客户端(运行AFNetworking的iPhone)的HTTP呼叫不再到达服务器。 但是,如果我重新启动我的node.js应用程序服务器,一切都会重新开始,直到事情不可避免地再次停止。 该应用程序从不崩溃,它只是停止响应请求。

我没有得到任何错误,我已经确保处理和logging所有数据库连接错误,所以我不知道从哪里开始。 我认为这可能与内存泄漏有关,所以我安装了node-memwatch并为内存泄漏build立了一个侦听器,但是在我的服务器停止响应请求之前,这个侦听器没有被调用。

任何线索可能会发生什么以及我如何解决这个问题?

这是我的堆栈:

  • AWS EC2 Micro Instance上的Node.js(使用Express 4.0 + PM2)
  • 运行MySQL的AWS RDS卷上的数据库(使用node-mysql)
  • 与node.js应用程序在同一个EC2实例上存储了与Redis相同的会话
  • 客户端是通过AFNetworking访问服务器的iPhone

上面提到的任何一个模块都没有发生错误。

首先,你需要更具体的超时。

  • TCP超时 :TCP将消息分成一个一个发送的数据包。 接收方需要确认收到了这个数据包。 如果接收方在一定时间内没有收到该包的确认,则发生TCP重传,即重新发送同一个包。 如果再次发生这种情况,发件人会放弃并终止连接。

  • HTTP超时 :HTTP客户端就像浏览器,或者你的服务器作为客户端(例如:向其他HTTP服务器发送请求),可以设置任意超时。 如果在这段时间内没有收到响应,它将断开连接并将其称为超时。

现在,有许多可能的原因,从更琐碎到更不重要:

  • 内容长度计算错误 :如果您发送带有Content-Length: 20标头的请求,则意味着“我要发送给您20个字节”。 如果发送19,则另一端将等待剩余的1.如果这需要太长的时间…超时。

  • 没有足够的基础设施 :也许你应该把更多的机器分配给你的应用 如果(total load / # of CPU cores)超过1,或者您的内存使用率很高,则说明系统可能超容量。 不过请继续阅读…

  • 无提示exception :引发错误,但没有logging到任何地方。 请求从未完成处理,导致下一个项目。

  • 资源泄漏 :每个请求都需要处理完成。 如果您不这样做,连接将保持打开状态。 另外, IncomingMesage对象(又名:通常称为req在快速代码中)将被其他对象(例如:expression自己)引用。 这些对象中的每一个都可以使用大量的内存。

  • 节点事件循环饥饿 :我会在最后谈到这一点。


对于内存泄漏,症状是:节点进程将使用越来越多的内存。

更糟糕的是,如果可用内存不足,并且服务器configuration错误以使用交换,Linux将开始将内存移动到磁盘(交换),这非常I / O和CPU密集型。 服务器不应该启用交换。

 cat /proc/sys/vm/swappiness 

将返回您在系统中configuration的swappiness级别(从0到100)。 您可以通过/etc/sysctl.conf (需要重新启动)或以不稳定的方式通过持久的方式修改它: sysctl vm.swappiness=10

一旦你确定你有内存泄漏,你需要得到一个核心转储并下载进行分析。 一个方法可以在这个其他的Stackoverflow响应中find: 从Node.js分析核心转储的工具

对于连接泄漏(您通过不处理完成请求而泄露连接),您将有越来越多的build立连接到您的服务器。 您可以使用netstat -a -p tcp | grep ESTABLISHED | wc -l检查已build立的连接 netstat -a -p tcp | grep ESTABLISHED | wc -l netstat -a -p tcp | grep ESTABLISHED | wc -l可以用来计算已build立的连接。

现在, 事件循环饥饿是最糟糕的问题。 如果你有短命的代码节点工作得很好。 但是,如果你使用CPU密集型的东西,并有一个function,使CPU繁忙的时间过长…像50毫秒(固体,阻塞,同步CPU时间50毫秒,而不是asynchronous代码50毫秒),操作由事件循环处理,如处理HTTP请求开始落后,最终超时。

findCPU瓶颈的方法是使用性能分析器。 nodegrind / qcachegrind是我的首选configuration工具,但其他人喜欢火焰图等。 然而,在生产中运行分析器可能很困难。 只需要一个开发服务器,并与请求大满贯。 又名:负载testing。 这有很多工具。


最后,debugging问题的另一种方法是:

env NODE_DEBUG=tls,net node <...arguments for your app>

节点具有通过NODE_DEBUG环境variables启用的可选debugging语句。 将NODE_DEBUG设置为tls,net将使节点发出tls和net模块的debugging信息…所以基本上所有的事情都被发送或接收。 如果有超时,你会看到它来自哪里。

来源:多年来维护大型节点服务部署的经验。