TL;博士
https://gist.github.com/anonymous/1e0faaa99b8bb4afe3749ff94e52c84f - 演示暗示泄漏的内存消耗。这是在我的代码中还是在 mysql 包中?
完整版:
我在我的程序中看到大量内存泄漏(最终每隔几个小时就会崩溃)。该程序通过 UDP 套接字接收大量数据,将相关位存储在内存中的哈希中,并每 10 秒将哈希中的数据写入 Mysql DB(AWS RDS 实例)一次。 node.js 版本是 6.9.4,在 RHEL 7.1 上运行
我尝试使用“--inspect”选项和 Chrome 开发工具进行一些分析,我最初怀疑是 mysql 包。为此,我制作了一个简单的 node.js 程序,该程序仅对本地数据库进行大量查询,并观察到它确实非常快地消耗了大量内存。这是程序:https://gist.github.com/anonymous/1e0faaa99b8bb4afe3749ff94e52c84f
我尝试了该程序的一些变体,所有这些变体都以明显指向内存不足崩溃的速度消耗内存。变化是:
上面的程序与内存数据库没有任何区别。它只做一件事:以高频率向 Mysql DB 发出大量 UPDATE 查询。
我将频率设置为 2 秒,以便轻松演示内存消耗情况。降低这个频率会减慢内存消耗,但它仍然会增长。它只是推迟了崩溃,但崩溃本身是不可避免的。
频率的实际使用要求是 10 秒,每次运行期间的更新查询数量将达到 10,000 次。因此示例程序中的数字非常接近现实世界的场景,而不仅仅是一些假设的模拟数字。
这是“--trace-gc”的输出,显示内存消耗在一分钟内上升到 400MB :
[29766:0x36c5120] 52326 ms: Scavenge 324.9 (365.1) -> 314.7 (369.1) MB, 8.3 / 0.0 ms [allocation failure].
[29766:0x36c5120] 53292 ms: Scavenge 330.3 (370.1) -> 317.4 (372.1) MB, 3.3 / 0.0 ms [allocation failure].
[29766:0x36c5120] 53477 ms: Scavenge 333.4 (374.1) -> 329.0 (375.1) MB, 15.6 / 0.0 ms [allocation failure].
[29766:0x36c5120] 53765 ms: Scavenge 335.5 (375.1) -> 331.9 (385.1) MB, 20.8 / 0.0 ms [allocation failure].
[29766:0x36c5120] 54701 ms: Scavenge 346.4 (386.1) -> 334.4 (388.1) MB, 5.3 / 0.0 ms [allocation failure].
[29766:0x36c5120] 55519 ms: Scavenge 349.9 (389.1) -> 338.9 (390.1) MB, 5.7 / 0.0 ms [allocation failure].
[29766:0x36c5120] 55614 ms: Scavenge 353.1 (392.1) -> 350.0 (395.1) MB, 17.8 / 0.0 ms [allocation failure].
[29766:0x36c5120] 56081 ms: Scavenge 356.8 (395.1) -> 351.3 (405.1) MB, 18.5 / 0.0 ms [allocation failure].
[29766:0x36c5120] 57195 ms: Scavenge 367.5 (406.1) -> 354.2 (407.1) MB, 3.2 / 0.0 ms (+ 20.1 ms in 236 steps since last GC) [allocation failure].
[29766:0x36c5120] 57704 ms: Scavenge 369.9 (408.1) -> 362.8 (410.1) MB, 12.5 / 0.0 ms (+ 15.7 ms in 226 steps since last GC) [allocation failure].
[29766:0x36c5120] 57940 ms: Scavenge 372.6 (412.1) -> 369.2 (419.1) MB, 21.6 / 0.0 ms (+ 8.5 ms in 139 steps since last GC) [allocation failure].
[29766:0x36c5120] 58779 ms: Scavenge 380.4 (419.1) -> 371.1 (424.1) MB, 11.4 / 0.0 ms (+ 11.3 ms in 165 steps since last GC) [allocation failure].
[29766:0x36c5120] 59795 ms: Scavenge 387.0 (426.1) -> 375.3 (427.1) MB, 10.6 / 0.0 ms (+ 14.4 ms in 232 steps since last GC) [allocation failure].
[29766:0x36c5120] 59963 ms: Scavenge 392.0 (431.3) -> 388.8 (434.3) MB, 19.1 / 0.0 ms (+ 50.5 ms in 207 steps since last GC) [allocation failure].
[29766:0x36c5120] 60471 ms: Scavenge 395.4 (434.3) -> 390.3 (444.3) MB, 20.2 / 0.0 ms (+ 19.2 ms in 96 steps since last GC) [allocation failure].
[29766:0x36c5120] 61781 ms: Scavenge 406.2 (446.3) -> 393.0 (447.3) MB, 3.7 / 0.0 ms (+ 107.6 ms in 236 steps since last GC) [allocation failure].
[29766:0x36c5120] 62107 ms: Scavenge 409.0 (449.3) -> 404.1 (450.3) MB, 16.0 / 0.0 ms (+ 41.0 ms in 227 steps since last GC) [allocation failure].
[29766:0x36c5120] 62446 ms: Scavenge 411.3 (451.3) -> 407.7 (460.3) MB, 22.6 / 0.0 ms (+ 20.2 ms in 103 steps since last GC) [allocation failure].
问题:
我非常乐意提供找出问题根源所需的任何其他信息。请告诉我。
在这里给出答案只是为了让面临类似问题的人受益。
就我而言,问题不是内存泄漏,而是吞吐量。我运行的 Mysql 服务器无法在如此短的时间内处理如此多的查询。这样的频率我简直要窒息 Mysql 服务器了。
Nodejs 只会为每个新查询创建一个新连接和/或一个查询对象。一旦查询完成,该对象将从内存中释放。但是客户端以如此高的频率发送如此多的查询,以至于 Mysql 服务器需要花费大量时间来完成每个查询。
简单地说,发出查询的速率远高于完成查询的速率。因此,查询/连接对象开始在客户端堆积,导致内存使用量不断增加。
这看起来像是泄漏。但事实并非如此。
我学到的一种区分泄漏和吞吐量问题的技术是停止创建工作(在本例中停止新查询)并检查内存使用量是否下降。如果是,则可能是吞吐量问题,如果不是,则可能是内存泄漏。
就我而言,每秒大约 8,000 个查询就可以正常工作。大约 8.5k 到 9k 会导致吞吐量问题,最终导致崩溃。
七年过去了,还没修好,在ts的mysql上。