Docs 菜单
Docs 主页
/
MongoDB Manual
/ /

在分片集群上滚动构建索引

在此页面上

  • Considerations
  • 开始之前
  • 步骤
  • 更多信息

索引构建可能会影响分片集群性能。默认情况下,MongoDB 在所有承载数据的副本集节点上同时构建索引。分片集群上的索引构建仅发生在包含要索引的集合的数据的分片上。对于无法容忍由于索引构建而性能下降的工作负载,请考虑使用以下过程以滚动方式构建索引。

滚动索引构建每次最多占用一个分片副本集节点(从从节点开始),并在该节点上单独构建索引。对于每个分片,滚动索引构建需要至少一次副本集选举。

注意

有关在Atlas中创建索引的信息,请参阅Atlas文档中的索引管理页面。

要通过以下过程创建 唯一索引 ,您必须在此过程中停止对集合的所有写入。

如果您在该过程中无法停止对集合的所有写入,请不要使用本页上的过程。相反,在分片集群的 mongos 上发出 db.collection.createIndex(),以在集合上构建唯一索引。

确保您的 oplog 足够大,以允许索引或重新索引操作完成,而不会落后太远而无法赶上。有关更多信息,请参阅 oplog 大小调整文档。

用于构建唯一索引
  1. 要使用以下过程创建唯一索引,您必须在索引构建期间停止对集合的所有写入。否则,可能在副本集节点之间具有不一致的数据。如果您无法停止对集合的所有写入,请不要使用以下过程创建唯一索引。

    警告

    如果无法停止对集合的所有写入,请勿使用以下步骤创建唯一索引。

  2. 在创建索引之前,请验证集合中是否有任何文档违反索引约束。 如果集合分布在分片上,并且分片包含具有重复文档的数据段,则创建索引操作可能会在没有重复项的分片上成功,但不会在有重复项的分片上成功。 为避免分片之间留下不一致的索引,您可以发出db.collection.dropIndex() 中的mongos 将索引从集合中删除。

从MongoDB 8.0开始,您可以使用directShardOperations角色执行需要直接对分片执行命令的分片操作。

警告

使用directShardOperations角色运行命令可能会导致集群停止正常工作,并可能导致数据损坏。 仅将directShardOperations角色用于维护目的或在MongoDB支持的指导下使用。 执行完维护操作后,请停止使用directShardOperations角色。

重要

以下过程采用滚动方式构建索引,适用于分片集群部署,不适用于副本集部署。有关副本集的操作过程,请参阅副本集上的滚动索引构建

mongosh 连接到分片集群中的 mongos 实例,然后运行 sh.stopBalancer() 以禁用负载均衡器:[1]

sh.stopBalancer()

注意

如果迁移正在进行,系统将在停止负载均衡器之前完成进行中的迁移。

要验证是否禁用了负载均衡器,请运行 sh.getBalancerState();如果已禁用负载均衡器,则会返回 false:

sh.getBalancerState()
[1] 从 MongoDB 6.0.3 开始,不再执行自动数据块分割。这是因为均衡策略的改进。自动分割命令仍然存在,但不执行操作。在 6.0.3 之前的 MongoDB 版本中,sh.stopBalancer() 还会为分片集群禁用自动分割。

从连接到 mongosmongosh 中,刷新该 mongos 的缓存路由表,以避免返回过时的集合分配信息。在刷新后,针对要构建索引的集合运行 db.collection.getShardDistribution()

例如,如果您要在 test 数据库中的 records 集合上创建升序索引:

db.adminCommand( { flushRouterConfig: "test.records" } );
db.records.getShardDistribution();

该方法输出分片分配。例如,考虑一个具有 3 个分片(shardAshardBshardC)的分片集群,db.collection.getShardDistribution() 返回以下内容:

Shard shardA at shardA/s1-mongo1.example.net:27018,s1-mongo2.example.net:27018,s1-mongo3.example.net:27018
data : 1KiB docs : 50 chunks : 1
estimated data per chunk : 1KiB
estimated docs per chunk : 50
Shard shardC at shardC/s3-mongo1.example.net:27018,s3-mongo2.example.net:27018,s3-mongo3.example.net:27018
data : 1KiB docs : 50 chunks : 1
estimated data per chunk : 1KiB
estimated docs per chunk : 50
Totals
data : 3KiB docs : 100 chunks : 2
Shard shardA contains 50% data, 50% docs in cluster, avg obj size on shard : 40B
Shard shardC contains 50% data, 50% docs in cluster, avg obj size on shard : 40B

根据输出,您只能在 shardAshardC 上构建 test.records 的索引。

对于包含集合数据段的每个分片,请按照在分片上构建索引的过程进行操作。

对于受影响的分片,停止与其从节点之一关联的 mongod 进程。在进行以下配置更新后,重新启动:

如果使用配置文件,请进行以下配置更新:

例如,对于分片副本集节点,更新后的配置文件将包含类似如下示例的内容:

net:
bindIp: localhost,<hostname(s)|ip address(es)>
port: 27218
# port: 27018
#replication:
# replSetName: shardA
#sharding:
# clusterRole: shardsvr
setParameter:
skipShardingConfigurationChecks: true
disableLogicalSessionCacheRefresh: true

并重新启动:

mongod --config <path/To/ConfigFile>

其他设置(例如storage.dbPath 等等)保持不变。

如果使用命令行选项,请进行以下配置更新:

例如,在不使用 --replSet--shardsvr 选项的情况下重启分片副本集节点。指定新的端口号并将 skipShardingConfigurationChecksdisableLogicalSessionCacheRefresh 参数均设置为 true:

mongod --port 27218 --setParameter skipShardingConfigurationChecks=true --setParameter disableLogicalSessionCacheRefresh=true

其他设置(例如--dbpath 等等)保持不变。

[2](12)通过在不同端口上运行 mongod 可以确保在构建索引时,副本集的其他节点及所有客户端不会联系该节点。

直接连接到在新端口上独立运行的 mongod 实例,并为该实例创建新索引。

例如,将 mongosh 连接到实例,并使用 db.collection.createIndex() 方法在 records 集合的 username 字段上创建一个升序索引:

db.records.createIndex( { username: 1 } )

索引构建完成后,关闭 mongod 实例。撤消以独立节点身份启动时所做的配置更改,以恢复其原始配置,并重新启动。

重要

请务必删除 skipShardingConfigurationChecksdisableLogicalSessionCacheRefresh 参数。

例如,要重新启动副本集分片成员:

如果您在使用配置文件:

net:
bindIp: localhost,<hostname(s)|ip address(es)>
port: 27018
replication:
replSetName: shardA
sharding:
clusterRole: shardsvr

其他设置(例如storage.dbPath 等等)保持不变。

并重新启动:

mongod --config <path/To/ConfigFile>

如果您使用的是命令行选项:

例如:

mongod --port 27018 --replSet shardA --shardsvr

其他设置(例如--dbpath 等等)保持不变。

允许复制赶上此节点。

一旦该节点赶上副本集中的其他节点,逐次逐个对剩余从节点重复该过程:

  1. C1. 停止一个从节点并重启为独立实例

  2. C2. 构建索引

  3. C. 以副本集节点身份重新启动 mongod 程序

当分片的所有从节点均有新索引时,分片的主节点降级,通过上述过程将其重启为独立运行的节点,然后在前一个主节点上构建索引:

  1. 使用 mongosh 中的 rs.stepDown() 方法将主节点降级。成功降级后,当前主节点将变为从节点,并且副本集成员会选举新的主节点。

  2. C1. 停止一个从节点并重启为独立实例

  3. C2. 构建索引

  4. C. 以副本集节点身份重新启动 mongod 程序

在完成构建分片的索引后,为其他受影响的分片重复执行 C. 在包含集合数据块的分片上构建索引

在完成受影响的分片的滚动索引构建后,重新启动负载均衡器。

mongosh 连接到分片集群中的 mongos 实例,然后运行 sh.startBalancer(): [3]

sh.startBalancer()
[3] 从 MongoDB 6.0.3 开始,不再执行自动数据块分割。这是因为均衡策略的改进。自动分割命令仍然存在,但不执行操作。在 6.0.3 之前的 MongoDB 版本中,sh.startBalancer() 还支持分片集群的自动分割。

如果一个分片集合在包含集合数据块的每个分片上没有完全相同的索引(包括索引选项),则该集合的索引不一致。尽管一般操作过程中不应出现索引不一致的情况,但这种情况仍有可能发生,例如:

  • 当用户使用 unique 键约束创建索引,且一个分片包含具有重复文档的数据段时。在此类情况下,创建索引操作可能会对没有重复项的分片成功完成,而对有重复项的分片失败。

  • 当用户以滚动方式跨分片创建索引,但未能为关联分片构建索引或错误地构建了具有不同规范的索引。

配置服务器主节点会定期检查分片集合的分片之间的索引不一致情况。要配置这些定期检查,请参阅 enableShardedIndexConsistencyCheckshardedIndexConsistencyCheckIntervalMS

在配置服务器主节点上运行时,命令 serverStatus 返回字段 shardedIndexConsistency 以报告索引不一致的情况。

要检查分片集合是否存在不一致的索引,请参阅查找分片间不一致的索引

后退

在副本集上创建