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