我试图了解在新的MongoDB(v 4.4)中分片的行为。
比方说,我的数据由可包含设备(多个组)的组(几个)组成。 所有这些设备将在一段时间(3-9个月)内存储一些与时间相关的值。
我最初的想法是为每24小时的数据创建一个设备文档(以避免达到16MB /文档的限制)。 这样,设备将类似于:
{
_id: ObjectId(...)
grp_id: ObjectId(...) // OR DBRef ?
time_bucket: ISODate(...)
data: {...} // data for the last 24 hours specified by time_bucket
}
现在进入分片键。
为了具有非单调性,我考虑使用{grp_id: "hashed"}
,因为这些将由用户分配,因此不会分配任何单调性。另外,smea组中的设备将位于同一碎片(在块限制内)。
但是组的基数和频率都很低,因此分片密钥应变为:{grp_id: "hashed", _id: 1}
。
但是,如果我随时间插入过多的设备数据,可能会造成麻烦,因此请再次优化密钥:{grp_id: "hashed", _id: 1, time_bucket: 1}
。这也具有很好的本地化数据能力,它将在特定时间段内仅针对碎片。
现在要回答的问题:
grp_id: "hashed"
,因为它是单调密钥,在密钥中包含_id: 1
会产生负面影响吗?_id
而不是grp_id
进行哈希处理,数据是否会在各个分片之间更均匀地分配(因为grp_id
与设备相比具有很高的频率和低基数)?密钥将为{_id: "hashed", grp_id: 1, time_bucket: 1}
。在这种情况下,grp_id
会有助于数据的局部性,以便将来自同一组的设备放置在相同的分片上吗?更笼统地说:我认为当使用散列键时,数据的分布方式有点困惑,而与基于范围的键结合使用另一个键,以及对于基于范围的键,您还可以定义区域的事实,我有点困惑(必须手动管理)。
我刚刚测试了两种分片方法,{grp_id: "hashed", _id: 1, time_bucket: 1}
(初始)与{_id: "hashed", grp_id: 1, time_bucket: 1}
(问题3):
第一种方法产生的碎片不平衡:
db.adminCommand({listDatabases:1, filter: {name: "test1"}})
{
"databases" : [
{
"name" : "test1",
"sizeOnDisk" : 22700032,
"empty" : false,
"shards" : {
"sharded-0" : 6377472,
"sharded-1" : 1425408,
"sharded-2" : 4210688,
"sharded-3" : 10686464
}
}
],
"totalSize" : 22700032,
"totalSizeMb" : 21,
"ok" : 1,
"operationTime" : Timestamp(1602680982, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1602680982, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
第二个产生平衡的碎片:
db.adminCommand({listDatabases:1, filter: {name: "test2"}})
{
"databases" : [
{
"name" : "test2",
"sizeOnDisk" : 21512192,
"empty" : false,
"shards" : {
"sharded-0" : 5152768,
"sharded-1" : 5185536,
"sharded-2" : 5218304,
"sharded-3" : 5955584
}
}
],
"totalSize" : 21512192,
"totalSizeMb" : 20,
"ok" : 1,
"operationTime" : Timestamp(1602682074, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1602682074, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
两个DB都包含6个组,每个组1000个设备,每个设备有30个实例(数据来自30天)。
我想知道背后的原因是什么,但我可能要问一个单独的问题。