在分片集群上滚动构建索引
索引构建可能会影响分片集群性能。默认情况下,MongoDB 在所有承载数据的副本集节点上同时构建索引。分片集群上的索引构建仅发生在包含要索引的集合的数据的分片上。对于无法容忍由于索引构建而性能下降的工作负载,请考虑使用以下过程以滚动方式构建索引。
滚动索引构建每次最多占用一个分片副本集节点(从从节点开始),并在该节点上单独构建索引。对于每个分片,滚动索引构建需要至少一次副本集选举。
注意事项
唯一索引
要使用以下过程创建唯一索引,必须在此过程中停止对集合的所有写入。
如果您在该过程中无法停止对集合的所有写入,请不要使用本页上的过程。相反,在分片集群的 mongos
上发出 db.collection.createIndex()
,以在集合上构建唯一索引。
Oplog 大小
确保您的 oplog 足够大,以允许索引或重新索引操作完成,而不会落后太远而无法赶上。有关更多信息,请参阅 oplog 大小调整文档。
先决条件
- 用于构建唯一索引
要使用以下过程创建唯一索引,您必须在索引构建期间停止对集合的所有写入。否则,可能在副本集节点之间具有不一致的数据。如果您无法停止对集合的所有写入,请不要使用以下过程创建唯一索引。
警告
如果无法停止对集合的所有写入,请勿使用以下步骤创建唯一索引。
在创建索引之前,请验证集合中是否有任何文档违反索引约束。 如果集合分布在分片上,并且分片包含具有重复文档的数据段,则创建索引操作可能会在没有重复项的分片上成功,但不会在有重复项的分片上成功。 为避免分片之间留下不一致的索引,您可以发出
db.collection.dropIndex()
中的mongos
将索引从集合中删除。
步骤
重要
以下过程采用滚动方式构建索引,适用于分片集群部署,不适用于副本集部署。有关副本集的操作过程,请参阅副本集上的滚动索引构建。
A. 停止负载均衡器
将 mongosh
连接到分片集群中的mongos
实例,然后运行sh.stopBalancer()
以禁用负载均衡器: [ 1 ]
sh.stopBalancer()
注意
如果迁移正在进行,系统将在停止负载均衡器之前完成进行中的迁移。
要验证是否禁用了负载均衡器,请运行 sh.getBalancerState()
;如果已禁用负载均衡器,则会返回 false:
sh.getBalancerState()
[1] | 从 MongoDB 6.0.3 开始,不再执行自动数据块分割。这是因为均衡策略的改进。自动分割命令仍然存在,但不执行操作。在 6.0.3 之前的 MongoDB 版本中,sh.stopBalancer() 还会为分片集群禁用自动分割。 |
B. 确定集合的分配情况
从连接到 mongos
的 mongosh
中,刷新该 mongos
的缓存路由表,以避免返回过时的集合分配信息。在刷新后,针对要构建索引的集合运行 db.collection.getShardDistribution()
。
例如,如果您要在 test
数据库中的 records
集合上创建升序索引:
db.adminCommand( { flushRouterConfig: "test.records" } ); db.records.getShardDistribution();
该方法输出分片分配。例如,考虑一个具有 3 个分片(shardA
、shardB
和 shardC
)的分片集群,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
根据输出,您只能在 shardA
和 shardC
上构建 test.records
的索引。
C. 在包含集合数据块的分片上构建索引
对于包含集合数据段的每个分片,请按照在分片上构建索引的过程进行操作。
C1. 停止一个从节点并重启为独立实例
对于受影响的分片,停止与其从节点之一关联的 mongod
进程。在进行以下配置更新后,重新启动:
[2] | (1、2)通过在不同端口上运行 mongod 可以确保在构建索引时,副本集的其他节点及所有客户端不会联系该节点。 |
C2. 构建索引
直接连接到在新端口上独立运行的 mongod
实例,并为该实例创建新索引。
例如,将 mongosh
连接到实例,并使用 db.collection.createIndex()
方法在 records
集合的 username
字段上创建一个升序索引:
db.records.createIndex( { username: 1 } )
C3 .以副本集成员身份重新启动程序mongod
索引构建完成后,关闭 mongod
实例。撤消以独立节点身份启动时所做的配置更改,以恢复其原始配置,并重新启动。
重要
请务必删除 skipShardingConfigurationChecks
和 disableLogicalSessionCacheRefresh
参数。
例如,要重新启动副本集分片成员:
允许复制赶上此节点。
C4. 对分片的剩余从节点重复该过程
一旦该节点赶上副本集中的其他节点,逐次逐个对剩余从节点重复该过程:
E. 在主节点上构建索引
当分片的所有从节点均有新索引时,分片的主节点降级,通过上述过程将其重启为独立运行的节点,然后在前一个主节点上构建索引:
使用
mongosh
中的rs.stepDown()
方法将主节点降级。成功降级后,当前主节点将变为从节点,并且副本集成员会选举新的主节点。
D. 对其他受影响的分片重复上述步骤
在完成构建分片的索引后,为其他受影响的分片重复执行 C. 在包含集合数据块的分片上构建索引。
E. 重新启动负载均衡器
在完成受影响的分片的滚动索引构建后,重新启动负载均衡器。
将 mongosh
连接到分片集群中的 mongos
实例,然后运行 sh.startBalancer()
: [3]
sh.startBalancer()
[3] | 从 MongoDB 6.0.3 开始,不再执行自动数据块分割。这是因为均衡策略的改进。自动分割命令仍然存在,但不执行操作。在 6.0.3 之前的 MongoDB 版本中,sh.startBalancer() 还支持分片集群的自动分割。 |
更多信息
如果一个分片集合在包含集合数据块的每个分片上没有完全相同的索引(包括索引选项),则该集合的索引不一致。尽管一般操作过程中不应出现索引不一致的情况,但这种情况仍有可能发生,例如:
当用户使用
unique
键约束创建索引,且一个分片包含具有重复文档的数据段时。在此类情况下,创建索引操作可能会对没有重复项的分片成功完成,而对有重复项的分片失败。当用户以滚动方式跨分片创建索引,但未能为关联分片构建索引或错误地构建了具有不同规范的索引。
配置服务器主节点会定期检查分片集合的分片之间的索引不一致情况。要配置这些定期检查,请参阅 enableShardedIndexConsistencyCheck
和 shardedIndexConsistencyCheckIntervalMS
。
在配置服务器主节点上运行时,命令 serverStatus
返回字段 shardedIndexConsistency
以报告索引不一致的情况。
要检查分片集合是否存在不一致的索引,请参阅查找分片间不一致的索引。