首先,您需要对超时有更具体的了解。
TCP 超时:TCP 将消息分成数据包,逐个发送。接收方需要确认已收到数据包。如果接收方在一定时间内未确认已收到数据包,则会发生 TCP 重传,即再次发送相同的数据包。如果这种情况再发生几次,发送者就会放弃并终止连接。
HTTP 超时:像浏览器这样的 HTTP 客户端,或者充当客户端的服务器(例如:向其他 HTTP 服务器发送请求),可以设置任意超时。如果在该时间内未收到响应,它将断开连接并称为超时。
现在,造成这种情况的可能原因有很多很多……从更微不足道到不那么微不足道:
内容长度计算错误:如果您发送带有Content-Length: 20
header,这意味着“我要向你发送 20 个字节”。如果您发送 19 个,另一端将等待剩余的 1 个。如果花费的时间太长...超时。
基础设施不足:也许您应该为您的应用程序分配更多机器。如果(total load / # of CPU cores)
超过 1,或者您的内存使用率很高,您的系统可能超出容量。然而继续阅读...
无声异常:抛出了一个错误,但没有记录在任何地方。该请求从未完成处理,导致下一个项目。
资源泄漏:每个请求都需要处理完成。如果您不这样做,连接将保持打开状态。除此之外IncomingMesage
对象(又名:通常称为req
在express代码中)将仍然被其他对象引用(例如:express本身)。这些对象中的每一个都可能使用大量内存。
节点事件循环饥饿: 我最后会讲到这一点。
对于内存泄漏,症状是:
节点进程将使用越来越多的内存。
更糟糕的是,如果可用内存较低并且您的服务器错误配置为使用交换,Linux 将开始将内存移动到磁盘(交换),这是 I/O 和 CPU 密集型的。服务器不应启用交换。
cat /proc/sys/vm/swappiness
将返回您系统中配置的交换级别(从 0 到 100)。您可以通过以下方式以持久方式修改它/etc/sysctl.conf
(需要重新启动)或以不稳定的方式使用:sysctl vm.swappiness=10
一旦确定存在内存泄漏,您需要获取核心转储并下载它以进行分析。可以在另一个 Stackoverflow 响应中找到一种方法:用于分析 Node.js 核心转储的工具
对于连接泄漏(由于未处理完成请求而泄漏了连接),与服务器建立的连接数量将会不断增加。您可以检查您已建立的连接netstat -a -p tcp | grep ESTABLISHED | wc -l
可用于对已建立的连接进行计数。
现在事件循环饥饿是最糟糕的问题。如果您的代码节点寿命较短,则效果很好。但是,如果您执行 CPU 密集型操作,并且有一个函数使 CPU 长时间处于繁忙状态...例如 50 毫秒(50 毫秒的固定、阻塞、同步 CPU 时间,而不是占用 50 毫秒的异步代码),则操作为由事件循环处理,例如处理 HTTP 请求开始落后并最终超时。
查找 CPU 瓶颈的方法是使用性能分析器。nodegrind
/qcachegrind
是我最喜欢的分析工具,但其他人更喜欢火焰图等。然而,在生产中运行分析器可能很困难。只需使用一个开发服务器并用请求来攻击它即可。又名:负载测试。有很多工具可以实现这一点。
最后,调试问题的另一种方法是:
env NODE_DEBUG=tls,net node <...arguments for your app>
节点有可选的调试语句,可以通过NODE_DEBUG
环境变量。环境NODE_DEBUG
to tls,net
将使节点发出 tls 和 net 模块的调试信息...所以基本上所有内容都被发送或接收。如果出现超时,您将看到它来自哪里。
Source:拥有多年维护节点服务大型部署的经验。