MongoDB Bucket upsert性能

MongoDB Bucket upsert性能,mongodb,mongodb-query,Mongodb,Mongodb Query,TL;医生: 我对bucket模型的升级速度比以更精细的格式插入同一文档慢10倍 背景: 我们将物联网数据存储在PSS MongoDB副本集中。目前,我们有一个小型模型,它以以下格式将每个传感器值保存在一个文档中: { _id: <ObjectId>, Time: <DateTime>, Value: <Object>, InternalId: <string> } { _id:, 时间:, 值:, 内部ID: } 对于我们当前

TL;医生: 我对bucket模型的升级速度比以更精细的格式插入同一文档慢10倍

背景: 我们将物联网数据存储在PSS MongoDB副本集中。目前,我们有一个小型模型,它以以下格式将每个传感器值保存在一个文档中:

{
  _id: <ObjectId>,
  Time: <DateTime>,
  Value: <Object>,
  InternalId: <string>
}
{
_id:,
时间:,
值:,
内部ID:
}
对于我们当前的服务器(512GB RAM、64个线程、NVMe磁盘),我们观察到每秒读取/写入超过200k,加起来。文档的平均大小为120字节,7天的数据总共有80亿个文档,这消耗了大约1TB的存储空间

我们现在正朝着桶模型的方向发展,以提高存储效率。目前,我正在使用建议的模型:

{
  _id: <ObjectId>,
  BlockStartTime: <DateTime>,
  BlockEndTime: <DateTime>,
  InternalId: <String>,
  LastModified: <DateTime>,
  Telemetry: [
    Key: <DateTime>,
    Value: <Object>,
    ...
  ]
}
{
_id:,
BlockStartTime:,
BlockEndTime:,
内部ID:,
上次修改:,
遥测:[
关键字:,
值:,
...
]
}
该模型在RAM使用和存储方面非常有效。但是,所有写入都非常慢。我使用以下命令插入遥测记录:

db.Telemetry.BulkWrite([
    {
        updateOne: {
            filter: { InternalId: <Guid>, BlockStartTime: <DateTime>},
            update: {
                $currentDate: { LastModified: true },
                $setOnInsert: { BlockEndTime: <DateTime>},
                $push: { Telemetry: { $each: [{ Key: <DateTime>, Value: <Object>}] }}
            },
            upsert: true
        }
]
db.Telemetry.BulkWrite([
{
更新日期:{
筛选器:{InternalId:,BlockStartTime:},
更新:{
$currentDate:{LastModified:true},
$setOnInsert:{BlockEndTime:},
$push:{遥测:{$each:[{键:,值:}]}
},
厄普塞特:是的
}
]
上面的BulkWrite通常包含25-775个查询,几乎总是包含一个要插入到“遥测”中的键值对

性能已从100K+写入/秒下降到5k/s-10k/s更新

我尝试了以下方法:

  • 删除$push,从而只设置LastModified日期。写入速度提高到15k/s。这是为了确定upserts是否是瓶颈
  • 将批处理大小从25个更新更改为775个更新,再更改为1500个更新,但运气不佳
  • 优化查询以充分使用索引。我可以确认
    .explain()
    说明索引只命中一次,并且只返回/获取一个文档
  • 服务器CPU(小于20%)和写入票证正常(始终大于120,最大为127)
  • 为每个遥测值插入一个存储桶,作为插入与插入的测试。性能比插入提高了3倍
  • 在4GB RAM服务器上进行测试。奇怪的是,在小型服务器上的性能稍低
  • 通过使用一个模拟器消除更新冲突的可能性,该模拟器每15秒发送一次遥测数据,按顺序分布在400K个唯一的内部ID上
我的问题: upsert是数据接收的方法吗?我可以理解性能下降了50%(upsert需要查找、更新或插入),但是10倍的下降是否正常?我的摄取策略是否遗漏了什么?我是否应该尝试仅以桶格式存储作为汇总策略,可能在摄取后一小时?我们需要为该客户端使用MongoDB