mongodb - MongoDB Bucket upsert 性能
问题描述
TL;DR: 我对桶模型的 upserts 比以更细粒度格式插入相同文档慢 10 倍。
背景: 我们将物联网数据存储在 PSS MongoDB 副本集中。目前,我们有一个小型模型,可以将每个传感器值保存在一个文档中,格式如下:
{
_id: <ObjectId>,
Time: <DateTime>,
Value: <Object>,
InternalId: <string>
}
使用我们当前的服务器(512GB RAM,64 个线程,NVMe 磁盘),我们观察到每秒 20 万次以上的读/写,加起来。文档平均大小为 120 字节,7 天数据总计 80 亿个文档,消耗大约 1TB 的存储空间。
我们现在正在转向存储桶模型以提高存储效率。目前,我正在使用以下建议的模型:
{
_id: <ObjectId>,
BlockStartTime: <DateTime>,
BlockEndTime: <DateTime>,
InternalId: <String>,
LastModified: <DateTime>,
Telemetry: [
Key: <DateTime>,
Value: <Object>,
...
]
}
该模型在 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
}
]
上面的 BulkWrite 通常包含 25 - 775 个查询,几乎总是包含一个键值对以插入“遥测”。
性能已从 100K+ 写入/秒下降到 5k/s - 10k/s 更新。
我尝试了以下方法:
- 删除 $push,从而仅设置 LastModified 日期。写入速度提高到 15k/s。这是为了确定 upserts 是否是瓶颈
- 将批量大小从 25 次更新更改为 775 次更新,再到 1500 次更新,但没有运气
- 优化查询以完全使用索引。我可以确认
.explain()
说明索引只被命中一次,并且只返回/获取一个文档 - 服务器 CPU(小于 20%)和写票是正常的(总是超过 120,最大为 127)
- 为每个遥测值插入一个存储桶作为插入与 upsert 的测试。性能从 upserts 提高了 3 倍
- 在 4GB RAM 服务器上进行测试。奇怪的是,小型服务器的性能略低
- 通过使用每 15 秒发送一次遥测数据、按顺序分布在 400K 唯一 InternalId 上的模拟器,消除更新冲突的可能性
我的问题: upsert 是数据摄取的方式吗?我可以理解性能下降 50%(upsert 需要查找,然后更新或插入),但是 10 倍下降正常吗?我的摄取策略是否遗漏了什么?我是否应该尝试仅以存储桶格式存储作为汇总策略,可能在摄取后一小时?我们需要为这个客户端使用 MongoDB
解决方案
推荐阅读
- django-rest-framework - 是否可以在 DRF web api 中提供身份验证令牌
- python - Python实时输出到Excel
- java - 在 ArrayList 中查找最常见的随机分配字符串
- abap - 以编程方式克隆使用逻辑数据库的程序
- visual-studio - 如何编写显示与基础文件不同的文本的扩展名?(如参数名称)
- java - 我在这个问题上的错误是什么。简单比较错误
- javascript - 更改我无法编辑的元素的 URL
- javascript - 如何为每个循环生成的 PHP 循环的每次迭代从列表中选择一个随机变量?
- python - “KeyError:标题”与 PyTube
- c - ISO C11 标准在哪里声明比较两个不指向同一个数组的指针是未定义的行为?