垃圾收集导致连接套接字延迟(NodeJS 服务器)

Garbage collection causes lag on connected sockets (NodeJS Server)

我在 Heroku 上托管一个 运行 在 NodeJS 服务器上的游戏网站。客户端使用包 socket.io 通过套接字连接。

偶尔触发垃圾收集周期时,连接的客户端会遇到严重的延迟,并且经常会断开连接。客户通过延迟传入的聊天和延迟的游戏输入体验到这一点。

当我查看日志时,我发现了与垃圾收集相关的错误消息。请参阅下面随附的日志。当这些 GC 事件发生时,有时它会导致大量内存峰值,以至于应用程序会超过允许的 0.5GB RAM 并被 Heroku 杀死。然而最近,内存峰值不再经常发生,但客户端的严重延迟仍然每天发生一到两次左右。

滞后的一个方面是通过聊天。当用户通过 "All Chat"(和任何聊天频道)键入消息时,服务器当前 console.log() 将其输出为标准。我碰巧在一次尖峰事件期间实时观看了日志,并注意到聊天输出到终端是实时的,没有延迟,但是客户端(我自己也作为客户端在网站上)收到了这些消息非常延迟的时尚。

我在网上发现了一个 NodeJS 错误(我认为已修复),当太多 console.loged 到屏幕时会导致严重的延迟,所以我 运行 通过发送一个压力测试每秒来自客户端的 1000 条消息,持续一分钟。我无法重现尖峰。

我已经阅读了很多关于查找内存泄漏、检查堆栈等的指南,但我非常不确定如何 运行 在实时 Heroku 服务器上进行这些测试。我怀疑我的游戏对象在关闭时没有被立即清除,而是立即被清除,导致内存峰值,但我没有信心。我不知道如何最好地调试它。我也很难实时捕捉到这种情况,因为只有超过 30 人登录时才会发生这种情况(这种情况并不经常发生,因为这仍然是一个相当小的网站)。

错误消息包括对我使用的 circular-json 模块的引用,我还怀疑这可能会以某种方式导致自身无限回调并且无法正确清除,但我不确定。

作为参考,这里是源代码的副本:LINK

这是发生尖峰时的一段记忆: Memory spike

崩溃日志 1:HERE

崩溃日志 2:HERE

有没有办法在本地模拟套接字或模拟实时服务器的环境(即连接的客户端)?

任何有关如何解决或调试此问题的建议都将不胜感激。谢谢。

需要考虑的一点是 console.log 会增加内存使用量。如果您使用大量数据进行详细记录,这可能会累积。快速查看日志,您似乎 运行ning 内存不足?这意味着该应用程序开始写入磁盘的速度较慢,并且还会 运行 垃圾收集激增 CPU。

这可能意味着内存泄漏,因为资源没有 killed/closed 而是简单地积累。调试它可以是一个 PITA。

Node 使用 1.5GB 来保存长期存在的对象。看起来你在一个 500mb 的容器上,所以最好将网络应用程序配置为像这样启动:

web: node --optimize_for_size --max_old_space_size=460 server.js

虽然您需要查明泄漏的根源,但您也可以通过 运行 设置多个 worker 和多个节点实例来提高可用性,并使用 socket.io-redis 来保持实例同步。我强烈推荐这条路线。

Some helpful content on Nodejs memory on Heroku.

您还可以通过节点脚本启动多个连接,以使用 socket.io-client 与您的本地开发服务器进行交互,并在本地监控内存并添加日志记录以确保正确关闭连接等。

我最终设法找到了我的 "memory leak"。事实证明,我过于频繁地将游戏(以 JSON 化字符串形式)保存到数据库中,server/database 跟不上。我已经降低了游戏保存的频率,并且没有遇到任何问题。

Samuel 提供的提示也很有帮助。