从事大型项目。几十个集合,每天 100 万用户,每秒 10,000+ 数据库事务。
我们只需将 Mongoose 的更新从 8.4.5 回滚到 8.2.0。 这会回滚许多其他软件包,包括转到旧版本的 mongodb、bson 等。
但这种行为是如此破坏,我找不到类似问题的任何其他报告,我正在寻找有关来源的提示。
虽然我怀疑这个
findOne
挂起发生在多个地方,但有一个明确的地方,因为我们跟踪同时处理的玩家查找数量。它挂在这里,从来没有撞到finally
。没有例外,只是挂了。也不是每次都是。它运行约 1 小时后开始挂起(因此我怀疑连接池超出或连接被回收)。
let player: DBPlayer | null;
try {
this.precheck++;
player = await models.Player.findOne({
_id: playerId, // playerId is a string representation of an ObjectId
})
.select({
_id: 1, // not necessary, but for clarity
authId: 1, // the only field we need
})
.lean(); // lean does a different code path in mongoose, so might be relevant
} finally {
this.precheck--;
}
在 8.4.5 大约一个小时后,我们看到我们的
precheck
数字缓慢上升,迅速增加,然后看起来稳定,然后再次爆发式上升。当然,发生的情况是我们的用户正在连接,但连接超时或者他们永远等待,因此他们刷新并重试。每次......都会在这里创建一个新的承诺并永远等待。即使超过30分钟,数字也不会下降。
models.Player
的创建方式如下:
models.Player = model<DBPlayer>('Player', schema)
模式不应该是相关的,但它相当复杂,包含映射、数组、分层对象等。所有这些都适用于 8.2.0
我怀疑这与创建新连接时的缓冲有关,但我在 mongoose 代码库中找不到在这些版本之间发生更改的代码。 文档表明缓冲就在初始连接之前,这肯定是成功的,因为我们正常运行了一个小时。
一个小时可能是回收连接的默认值,在这种情况下,它确实不起作用。
删除使用同一会话进行并行查询的情况解决了该问题。该行为是明确“未定义”的,虽然它在早期的 mongo 版本中有效,但它不再有效并破坏连接状态。
底线,绝对不要使用同一会话进行并行查询!