具有复合哈希分片密钥的MongoDB

问题描述

我试图了解在新的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}。这也具有很好的本地化数据能力,它将在特定时间段内仅针对碎片。

现在要回答的问题:

  1. 这种方法在理论上会起作用吗?
  2. 如果我已经包含grp_id: "hashed",因为它是单调密钥,在密钥中包含_id: 1会产生负面影响吗?
  3. 如果我对_id而不是grp_id进行哈希处理,数据是否会在各个分片之间更均匀地分配(因为grp_id与设备相比具有很高的频率和低基数)?密钥将为{_id: "hashed",grp_id: 1,time_bucket: 1}在这种情况下,grp_id会有助于数据的局部性,以便将来自同一组的设备放置在相同的分片上吗?

更笼统地说:我认为当使用散列键时,数据的分布方式有点困惑,而与基于范围的键结合使用另一个键,以及对于基于范围的键,您还可以定义区域的事实,我有点困惑(必须手动管理)。

我刚刚测试了两种分片方法{grp_id: "hashed",time_bucket: 1}(初始)与{_id: "hashed",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,"signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)
                }
        }
}

第二个产生平衡的碎片:

db.adminCommand({listDatabases:1,filter: {name: "test2"}})
{
        "databases" : [
                {
                        "name" : "test2","sizeOndisk" : 21512192,"shards" : {
                                "sharded-0" : 5152768,"sharded-1" : 5185536,"sharded-2" : 5218304,"sharded-3" : 5955584
                        }
                }
        ],"totalSize" : 21512192,"totalSizeMb" : 20,"operationTime" : Timestamp(1602682074,1),"$clusterTime" : {
                "clusterTime" : Timestamp(1602682074,"keyId" : NumberLong(0)
                }
        }
}

两个DB都包含6个组,每个组1000个设备,每个设备有30个实例(数据来自30天)。

我想知道背后的原因是什么,但我可能要问一个单独的问题。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)