随着收集量的增加(文档数量),Upsert性能下降

ken*_*tor 6 javascript performance upsert mongodb node.js

使用案例:

我正在使用REST Api来提供视频游戏的战斗结果.这是一个团队与团队在线游戏,每个团队由3名玩家组成,他们可以从100个不同角色中选择不同的角色.我想计算每个球队组合的胜负数和平局数.我每秒大约获得1000次战斗结果.我连接每个团队的角色ID(升序)然后我保存每个组合的赢/输和抽奖.

我目前的实施:

const combinationStatsSchema: Schema = new Schema({
  combination: { type: String, required: true, index: true },
  gameType: { type: String, required: true, index: true },
  wins: { type: Number, default: 0 },
  draws: { type: Number, default: 0 },
  losses: { type: Number, default: 0 },
  totalGames: { type: Number, default: 0, index: true },
  battleDate: { type: Date, index: true, required: true }
});
Run Code Online (Sandbox Code Playgroud)

对于每个返回的日志,我执行upsert并将这些查询批量发送(5-30行)到MongoDB:

const filter: any = { combination: log.teamDeck, gameType, battleDate };
if (battleType === BattleType.PvP) {
  filter.arenaId = log.arena.id;
}
const update: {} = { $inc: { draws, losses, wins, totalGames: 1 } };
combiStatsBulk.find(filter).upsert().updateOne(update);
Run Code Online (Sandbox Code Playgroud)

我的问题:

只要我在我的收藏中只有几千个条目,combinationStatsmongodb只需要0-2%的cpu.一旦该集合有几百万个文档(由于可能的组合数量很快发生),MongoDB不断占用50-100%的CPU.显然我的方法根本不可扩展.

我的问题:

这些选项中的任何一个都可以解决我上面定义的问题:

  1. 我可以优化上面描述的MongoDB解决方案的性能,以便它不需要那么多CPU吗?(我已经将我过滤的字段编入索引,并且我批量执行upsert).是否有助于创建一个哈希(基于我的所有过滤器字段),我可以使用它来过滤数据然后提高性能?
  2. 是否有更适合汇总此类数据的数据库/技术?我可以想象一些我想要/需要为给定标识符递增计数器的用例.

编辑:在khang评论说它可能与upsert表现有关后,我$inc用a 取而代之$set,而且表现同样"差".因此我尝试了建议find()然后手动update()方法,但结果没有变得更好.

ken*_*tor 2

根据您的过滤条件创建哈希:

我能够将 CPU 从 80-90% 降低到 1-5%,并体验到更高的吞吐量。

显然是过滤器的问题。我没有根据这三个条件进行过滤:{ combination: log.teamDeck, gameType, battleDate }我在节点应用程序中创建了一个 128 位哈希。我使用此哈希进行更新插入,并将组合、gameType 和 BattleDate 设置为更新文档中的附加字段。

为了创建哈希,我使用了 Metrohash 库,可以在这里找到该库: https: //github.com/jandrewrogers/MetroHash。不幸的是,我无法解释为什么性能如此好,特别是因为我索引了之前的所有条件。