mongodb 为什么Mongoose v6和v7导致垃圾收集和事件循环延迟比v5显著增加?

8yoxcaq7  于 2023-08-04  发布在  Go
关注(0)|答案(1)|浏览(80)

背景:在过去的一年里,我们一直试图在SaaS平台中从Mongoose v5迁移到v6,但没有成功。运行Mongoose 7时也会出现此处描述的问题。我们的软件有相当数量的Web流量(大约每秒25个请求),并且使用单个MongoDB Atlas集群,其中每个SaaS客户端都使用自己的数据库。该软件托管在Heroku上。
问题:当我们部署一个使用Mongoose 6或7的软件版本时,它可以正常运行长达一个小时,然后我们开始看到垃圾收集的数量,垃圾收集花费的时间和事件循环延迟的增加。这种情况一直持续到服务器事件循环被完全占用并且无法处理更多的传入请求。内存使用不受影响,所以看起来不像是内存泄漏。
代码:
启动时,我们创建一个数据库连接,池中有300个连接:

global.databaseConnection = await mongoose.createConnection(global.config.dbConnectionString, {
    maxPoolSize: 300,
    minPoolSize: 300
});

字符串
当接收到对特定客户端的请求时,使用useDb函数从连接池中提取到该特定客户端数据库的连接:

clientDatabaseConnection = global.databaseConnection.useDb(`client-${client.databaseName}`, {
    noListener: true,
    useCache: true
});


然后,客户端数据库连接用于执行请求所需的各种查询,例如:

let clientUserCollection = connection.model<IClientUserModel>("ClientUser", ClientUserSchema, 'users');
let user = await clientUserCollection.findById(userId).exec();


这基本上就是应用程序的结构。与v5相比,v6和v7中有什么不同之处会导致这些性能影响?
我已经尝试调整连接池的大小,但这没有帮助。

f4t66c6m

f4t66c6m1#

我们可能遇到了类似的问题。我们也在使用Heroku、MongoDB Atlas和Mongoose。我们还为每个客户端提供了一个数据库。
过去,我们每个客户端都有一个应用程序。但一年前,我们改用了一个多租户架构,在一个heroku应用程序上有几个客户端,每个客户端都有自己的数据库(我们有几个这样的应用程序,每个应用程序上大约有20个客户端)。在实施架构的同时,我们也从Mongoose 5迁移到了Mongoose 6(我们现在使用的是7)。“
我们目前使用的是createConnection,并将其存储在一个Map中,而不是useDb,但我们也尝试了useDb,并遇到了同样的问题。
今天,我们通过定期重启dynos来实现这一点。这显然是权宜之计。
在我们的例子中,很明显,当许多客户端连接到同一个应用程序时,就会发生崩溃。内存似乎增加了,所以我们怀疑问题是由于我们如何管理mongoose连接和模型存储,但我们试图转移到dynos与更多的内存,它崩溃的方式之前,内存限制。所以,和你的情况一样,这似乎不是内存泄漏。

编辑
1.填充中的无限循环

因此,在我们的示例中,我们发现在某些情况下infinite task (loop)是由嵌套的populate生成的。它不会一直中断,而是在同时连接到多个数据库时中断。我们不知道它是否与正在进行填充或其他操作时断开的连接有关。
人口是这样的:

ModelA.find(...)
  .populate([
    {
      path: 'propertytOfA',
      populate: {
        path: 'propertyB', // has discriminator
        populate: { path: 'propertyC' } // has discriminator
      }
    }
  ])

字符串
这里重要的一点可能是最后两个集合都有鉴别器。我想知道这是否就是这里的 Mongoose 迁移指南中所称的recursive embedded discriminators

**2.maxPoolSize *

您说您尝试更改此参数,但没有任何帮助。
在我们的例子中,在解决了无限任务后,我们开始看到其他问题,例如Client network socket disconnected before secure TLS connection was established',所以我们决定尝试调整maxPoolSize
我们将其设置为5(Mongoose 5上的默认值,在Mongoose 6中增加为100),它似乎解决了我们的问题。

相关问题