mongodb - 分片键 - 复合 vs 散列

mongodb - shard key - compound vs hash

我正在使用现有的 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):

You may not create compound indexes that have hashed index type. You will receive an error if you attempt to create a compound index that includes a hashed

我想这意味着这个问题不明智,所以我会关闭。

编辑 2:再想一想,这个问题是有效的,但这样表述会更好——我似乎有两个选择:

  1. 散列 post.id 字段,该字段应该是唯一的,如果散列将有助于确保数据在分片之间均匀分布,或者

  2. 创建一个user_id和post.id的组合键,如上面的代码。这也将保证唯一性,并且应该有助于单个用户的数据局部性。 但是它能保证跨分片的数据均匀分布吗?

谢谢

Hash the post.id field, which should be unique, and if hashed will help ensure even distribution of data across shards

如果您的 ID 是单调的(根据当前示例),我会强烈考虑使用 UUIDs/GUIDs,它可以在不依赖中央序列的情况下生成。除非您的序列号由另一个记录系统提供,否则它们将为需要声明下一个可用编号的分布式客户端带来扩展和协调挑战。 GUID 可以通过散列更有效地实现您想要的结果。

MongoDB 的默认值 ObjectId 是为此目的设计的一个示例:一个伪随机 12 字节值,可以在分布式环境中独立生成,具有基于前导时间戳。

生成自定义 UUID 不在 MongoDB 的范围内,但如果您有其他要求(长度、值的范围、顺序、冲突的可能性,...),有许多可用的 algorithms/libraries 用于生成 UUID 或者您可以创建自己的公式。

分片键值的基数决定了您是否会得到有效的数据分布。假设原始值中存在基数,散列分片键有助于分配初始写入:这基本上将序列从单调递增更改为统一。

Create a composite key of user_id and post.id, like the code above. This will also guarantee uniqueness, and should help with data locality for a single user. But will it ensure even data distribution across shards?

片键需要高基数,但不一定必须是唯一的。例如,如果您在 {month:1}(代表一年中的月份)的单个字段上进行分片,则该字段只有 12 个可能的值。单个月的所有数据最终将在单个分片上,因此如果第 5 个月的值多于第 11 个月的值,则数据分布本质上是不均匀的。 MongoDB 的 data distribution 用于分片集合是基于能够自动将分片键划分为逐渐变小的键范围(称为 )。一个潜在的假设是每个块代表大致相等的数据范围(平均),并且块在分片之间的均匀分布将导致平衡。

对于您的用例,假设您解决了 ID 单调递增的问题,{user_id, post.id} 似乎是一个可能的复合分片键。这似乎符合我上面提到的三个方面。

但是,与其猜测分片键结果,我建议在开发环境中对此进行测试。

如果您对数据模型和分布模式有很好的理解或估计,我建议在测试环境中使用代表性数据进行分片。如果需要,有许多有用的工具可用于生成虚假(但概率性)数据。有关使用模式分析和 "more like this" 方法的示例配方,请参阅:duplicate a collection into itself.