MongoDB分片键

MongoDB分片键,mongodb,sharding,Mongodb,Sharding,我们有一个庞大的MongoDB集合,我们想开始切分。该集合有3.4B条记录,大小约为14.6TB(磁盘上压缩了5.3TB)。这一系列作品的写作速度通常为每小时约500万次,但我们预计这一速度将逐年增长。此集合上的索引大小约为220GB 所有记录都有一个feedId,所有查询都将针对属于特定feedId的记录。目前约有200个唯一的feedId值,但每个值的分布高度非线性。在低端,一些feedId每天可能只能看到几十条记录。另一方面,前5个feedId占数据集的75% 记录也有一个时间戳,查询总是

我们有一个庞大的MongoDB集合,我们想开始切分。该集合有3.4B条记录,大小约为14.6TB(磁盘上压缩了5.3TB)。这一系列作品的写作速度通常为每小时约500万次,但我们预计这一速度将逐年增长。此集合上的索引大小约为220GB

所有记录都有一个
feedId
,所有查询都将针对属于特定
feedId
的记录。目前约有200个唯一的
feedId
值,但每个值的分布高度非线性。在低端,一些feedId每天可能只能看到几十条记录。另一方面,前5个feedId占数据集的75%

记录也有一个
时间戳
,查询总是针对给定的日期范围。
时间戳
字段或多或少是单调的

feedId
timestamp
上已经存在复合索引

此集合的典型工作集仅为最近几周的数据,因此仅占实际数据的很小百分比。对该数据的查询必须非常快,对历史数据的查询速度较慢是可以接受的。因此,我们计划使用“标签”和/或“区域”将较旧的数据移动到具有较大HDD的节点,并使用具有SSD的节点来处理“热”数据


基于这些因素,使用
{feedId:1,timestamp:1}
的切分键是否合理?我的感觉是,由于
feedId
的非线性和
时间戳的单调性,它可能会导致“热”节点。在密钥中添加一个“哈希”字段会使它更好/更差吗?

所以让我们一点一点地来看看这个

该集合有3.4B条记录,大小约为14.6TB(磁盘上压缩了5.3TB)

切分的本质是这样的,所以第一次正确地进行切分非常重要。我将在这里详细介绍,但是TL;博士是:

  • 将数据集的一部分(例如使用
    mongodump--query
    )提取到暂存集群(例如使用
    mongorestore
  • 将示例工作负载指向临时集群以模拟您的生产环境
  • 测试一个或多个切分键组合。根据需要转储/重新加载,直到您对性能感到满意
现在,让我们深入探讨:

目前有约200个唯一的feedId值,但每个值的分布高度非线性。在低端,一些feedId每天可能只能看到几十条记录。另一方面,前5个feedId占数据集的75%

因此,一个支持大量查询的字段的频率非常低。如果你只是在这个场地上切分,你肯定会看到热点

记录也有时间戳,查询总是针对给定的日期范围。时间戳字段或多或少是单调的

因此,另一个字段支持大多数查询,但对切分也不是很好

记录也有时间戳,查询总是针对给定的日期范围。时间戳字段或多或少是单调的

对我来说,这意味着你查询的主要字段是基于时间的。在给定的时间段内,给我指定feedID的文件。您还将获得有针对性的查询,因为您在shard键上的查询频率比在其他键上的查询频率要高(例如,在一个时间范围内,或者在一个时间范围内+feedId

这也支持您分区的想法:

因此,我们计划使用“标签”和/或“区域”将较旧的数据移动到具有较大HDD的节点,并使用具有SSD的节点来处理“热”数据

通过分区,您可以使用分片密钥中的任何密钥,只要包含该密钥之前的整个前缀。因此,
{feedId:1,timestamp:1}
主要支持feedId和timestamp上的区域,这并不是您想要的

仅基于此,我敢说,
{timestamp:1,feedId:1}
将是一个不错的选择。您的测试需要研究的是是否添加 低频场到单调递增场提供了良好的组块分布

现在,关于散列:

在密钥中添加“哈希”字段会使其更好/更糟吗

如果您的意思是,您的文档已经有一些散列字段,那么您可以添加这些字段,只是为了随机性。但如果你说的是一个散列切分键,那就不同了

分区和散列碎片键不能一起玩。哈希切分键的性质意味着块范围(因此区域)表示哈希切分键值。因此,即使您有两个值彼此非常接近的文档,它们也可能最终位于完全不同的块上。因此,在一系列散列切分键值上创建一个区域可能无法完成您希望它完成的任务。您可以做一些事情,比如使用带有散列切分的区域将整个集合移动到集群中切分的子集上,但这不是您想要做的

现在,您可能会遇到一个关键问题—您的收藏量很大。您选择的shard键可能会导致MongoDB尝试将数据划分为块的初始拆分出现问题。请查看我们文档中的以下部分:。这里有一个公式可供您使用,用于估计配置的区块大小(默认情况下为64MB)下您的碎片密钥可以支持的最大集合大小。我猜您需要先将块大小增加到128MB,或者可能是256MB。这仅适用于初始分片过程。之后,您可以将块大小减少回默认值,并让MongoDB处理其余部分

请注意,这将对性能产生影响。您将有块在碎片之间迁移,p