我正在使用现有的mongodb集合。数据如下所示:
{ user_id: 123, post: { id: 123456789, title: "..." } },
{ user_id: 123, post: { id: 123456790, title: "..." } },
{ user_id: 124, post: { id: 123456791, title: "..." } }
我需要对此集合进行分片,而我在选择分片键时遇到问题。我经常基于用户执行操作(例如,获取来自用户123的所有帖子)。我应该根据
创建分片键{
user_id: 1,
post.id: 1
}
或相同,但是哈希?
如果是哈希,我假设范围查询将广播到所有分片。但如果不哈希,文档是否会在分片中均匀分布?您可以看到值单调增加。
谢谢,
编辑:我认为我犯了一个错误,似乎复合索引不能被哈希。从文档(https://docs.mongodb.com/manual/core/index-compound):您可能无法创建具有散列索引类型的复合索引。如果您尝试创建包含散列
的复合索引,则会收到错误
我想这意味着这个问题不合理,所以我会关闭。
编辑2:第二个想法,问题是有效的,但它会更好地表达 - 我似乎有两个选择:
散列post.id字段,该字段应该是唯一的,如果散列有助于确保跨分片均匀分布数据,或者
创建user_id和post.id的复合键,就像上面的代码一样。这也将保证唯一性,并且应该有助于单个用户的数据位置。 但是它会确保跨分片的数据分布吗?
由于
答案 0 :(得分:1)
散列post.id字段,该字段应该是唯一的,如果散列将有助于确保跨分片均匀分布数据
如果您的ID是单调的(根据当前示例),我强烈考虑使用UUIDs/GUIDs,可以在不依赖中心序列的情况下生成ObjectId
。除非您的序列号由另一个记录系统提供,否则它们将为需要声明下一个可用号码的分布式客户端引入扩展和协调挑战。 GUID可以更有效地实现您以散列为目标的结果。
MongoDB的默认data distribution是为此目的而设计的一个示例:伪随机12字节值,可以在分布式环境中独立生成,并根据前导时间戳进行近似排序。 / p>
生成自定义UUID超出了MongoDB的范围,但如果您有其他要求(长度,值范围,排序,碰撞可能性......),则有许多可用的算法/库用于生成UUID,或者您可以创建你自己的公式。
分片键值的基数决定了您是否会获得有效的数据分发。假设原始值中存在基数,散列的分片键有助于分配初始写入:这基本上将序列从单调增加变为均匀。
创建user_id和post.id的复合键,就像上面的代码一样。这也将保证唯一性,并且应该有助于单个用户的数据位置。 但是它会确保跨分片的数据分布吗?
分片键需要高基数,但不一定必须是唯一的。例如,如果您对单个字段进行分片{month:1}
(表示一年中的几个月),则此字段只有12个可能的值。单个月的所有数据将以单个分片结束,因此如果第5个月的值多于第11个月,则数据分布将固有地不均匀。 MongoDB的duplicate a collection into itself用于分片收集是基于能够自动将分片键划分为逐渐变小的键范围(称为块)。一个潜在的假设是每个块代表一个大致相等的数据范围(平均),并且跨分片的块的均匀分布将导致平衡。
对于您的用例,{user_id, post.id}
似乎是一个可能的复合分片键,假设您解决了单调增加ID的问题。这似乎符合我上面提到的三个方面。
然而,我建议在开发环境中测试一下,而不是猜测碎片关键结果。
如果您对数据模型和分布模式有很好的理解或估计,我建议使用代表性数据在测试环境中进行分片。如果需要,有许多有用的工具可用于生成虚假(但概率)数据。对于使用模式分析的示例配方和更多类似的"方法,请参阅:comparable。