nodejs mysql内存泄漏大量高频查询

时间:2017-05-21 21:53:29

标签: mysql node.js memory-leaks node-mysql

TL; DR

https://gist.github.com/anonymous/1e0faaa99b8bb4afe3749ff94e52c84f - 显示意外泄漏的内存消耗。这是在我的代码中还是在mysql包中?

完整版:

我在程序中看到很多内存泄漏(并且每隔几个小时最终崩溃)。该程序通过UDP套接字接收大量数据,将相关位存储在内存中的Hash中,并每隔10秒将其Hash中的数据写入Mysql DB(AWS RDS实例)一次。 node.js版本是6.9.4,在RHEL 7.1上运行

我尝试使用" - inspect"进行一些分析。选项和Chrome devtools以及我最初的怀疑是mysql包。为此,我创建了一个简单的node.js程序,该程序只对本地数据库进行了大量查询,并发现它确实非常快地消耗了大量内存。这是程序:https://gist.github.com/anonymous/1e0faaa99b8bb4afe3749ff94e52c84f

我尝试了一些程序的变体,所有这些变量都消耗了内存,其速度明显指向内存不足崩溃。变化是:

  1. 使用单一连接
  2. 使用具有30个连接的池(这是生产设置)
  3. 使用有效的查询语句
  4. 使用导致解析错误的无效查询语句(第27行上字符串123之前的空格使其成为错误查询。删除空格使得它是有效查询)
  5. 以上程序与内存数据库没有任何区别。它只做一件事:以高频率向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].
    

    问题:

    1. 对于这么多查询,这种内存消耗是否是预期的,或者这表明存在泄漏?
    2. 我的代码是否泄漏了内存?我错过了哪些明显的东西?我是以错误的方式使用包裹吗?
    3. 如果这确实是包装中的泄漏,在泄漏修复之前是否有任何直接的解决方法?
    4. 我非常乐意提供任何其他信息,以便找到根源。请告诉我。

1 个答案:

答案 0 :(得分:1)

在这里给出答案只是为了面对类似问题的任何人的利益。

在我的情况下,问题不是内存泄漏,而是吞吐量。我运行的Mysql服务器无法在如此短的时间内处理如此多的查询。有了这样的频率,我只是窒息了Mysql服务器。

Nodejs将继续为每个新查询创建新连接和/或查询对象。查询完成后,此对象将从内存中释放。但客户端发送的查询频率如此之高,以至于Mysql服务器花了很多时间来完成每个查询。

简单地说,查询的速度远远高于完成查询的速率。因此,查询/连接对象刚刚开始堆积在客户端,导致内存使用量不断增加。

这看起来像是泄漏。但它不是。

我在区分泄漏和吞吐量问题时学到的一种技术是停止创建工作(在这种情况下停止新查询)并检查内存使用是否出现故障。如果它确实那么它是吞吐量问题,如果不是,它可能是内存泄漏。

就我而言,每秒最多约8,000个查询可以正常工作。大约8.5k到9k会导致吞吐量问题,最终导致崩溃。