分片集群索引构建
索引构建可能会影响分片集群的性能。默认情况下,MongoDB同时在整个数据副本集成员上构建索引。分片集群上的索引构建仅发生在包含要索引的集合数据的那些分片上。对于不能容忍由于索引构建导致的性能下降的工作负载,请考虑使用以下步骤以滚动方式构建索引。
滚动索引构建每次最多从分片副本集成员中移出一个,从次要成员开始,在该成员上独立构建索引。滚动索引构建需要每个分片至少进行一次副本集选举。
注意
有关在Atlas中创建索引的信息,请参阅索引管理页面中的Atlas文档。
注意事项
唯一索引
创建唯一索引时,必须在此过程中停止对集合的所有写入。
如果在执行此过程中无法停止对集合的所有写入,请不要使用本页上的该程序。相反,通过在db.collection.createIndex()
上执行操作来构建集合的唯一索引。
Oplog Size
开始之前
- 构建唯一索引
使用以下程序创建唯一索引时,必须在索引构建期间停止对集合的所有写入。否则,您可能会在副本集成员之间出现不一致的数据。如果无法停止对集合的所有写入,请不要使用以下程序来创建唯一索引。
警告
如果无法停止对集合的所有写入,请不要使用以下程序来创建唯一索引。
在创建索引之前,请验证集合中没有文档违反索引约束。如果一个集合分布在多个分片中,并且一个分片包含有重复文档的数据块,则创建索引操作可能在没有重复数据的分片上成功,但在有重复数据的分片上失败。为了避免在分片之间留下不一致的索引,您可以从
db.collection.dropIndex()
中发出命令,从mongos
删除集合中的索引。
从MongoDB 8.0开始,您可以使用directShardOperations
角色来执行需要直接对分片执行命令的维护操作。
警告
使用directShardOperations
角色运行命令可能会导致您的集群无法正确工作,并可能导致数据损坏。仅将directShardOperations
角色用于维护目的或MongoDB支持的指导下。完成维护操作后,停止使用directShardOperations
角色。
程序
重要
以下以滚动方式构建索引的程序适用于分片集群部署,而不是副本集部署。有关副本集的程序,请参阅副本集上的滚动索引构建。
A. 停止均衡器
将mongosh
连接到分片集群中的mongos
实例,并运行sh.stopBalancer()
以禁用均衡器:[1]
sh.stopBalancer()
注意
如果正在进行迁移,系统将在停止均衡器之前完成正在进行的迁移。
要验证均衡器是否已禁用,请运行sh.getBalancerState()
,如果均衡器已禁用,则返回false
sh.getBalancerState()
[1] | 从MongoDB 6.0.3版本开始,不再执行自动分片分割。这是因为平衡策略的改进。自动分割命令仍然存在,但不执行任何操作。在MongoDB 6.0.3之前的版本中,sh.stopBalancer() 还禁用了分片集群的自动分割。 |
B. 确定集合的分布
从连接到mongosh
的mongos
,刷新该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
进程。在执行以下配置更新后重新启动:
如果使用配置文件,请执行以下配置更新
取消注释
replication.replSetName
选项。取消注释
sharding.clusterRole
选项。在
setParameter
部分中将参数skipShardingConfigurationChecks
设置为true
。在
setParameter
部分中将参数disableLogicalSessionCacheRefresh
设置为true
。
例如,对于一个分片副本集成员,更新的配置文件将包含以下示例内容:
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
;如果是配置服务器成员,则删除--configsvr
。在
--setParameter
选项中将参数skipShardingConfigurationChecks
设置为true
。在
--setParameter
选项中将参数disableLogicalSessionCacheRefresh
设置为true
。
例如,在不带 --replSet
和 --shardsvr
选项的情况下重启您的分片副本集成员。指定新的端口号,并将 skipShardingConfigurationChecks
和 disableLogicalSessionCacheRefresh
参数设置为 true
mongod --port 27218 --setParameter skipShardingConfigurationChecks=true --setParameter disableLogicalSessionCacheRefresh=true
其他设置(例如 --dbpath
等)保持不变。
[2] | (1, 2) 通过在另一个端口上运行 mongod ,您确保在构建索引期间副本集的其他成员和所有客户端都不会接触该成员。 |
C2. 构建 Index
直接连接到在新端口上作为独立实例运行的 mongod
实例,并为该实例创建新的索引。
例如,连接 mongosh
到该实例,并使用 db.collection.createIndex()
方法在 records
集合的 username
字段上创建一个升序索引
db.records.createIndex( { username: 1 } )
C3. 重新启动程序 mongod
作为副本集成员
当索引构建完成后,关闭 mongod
实例。撤销以独立模式启动时所做的配置更改,以返回其原始配置并重新启动。
重要
请务必删除参数 skipShardingConfigurationChecks
和 disableLogicalSessionCacheRefresh
。
例如,要重新启动您的副本集分片成员
如果您正在使用配置文件
恢复到原始端口号。
在
setParameter
部分中删除参数skipShardingConfigurationChecks
。在
setParameter
部分中删除参数disableLogicalSessionCacheRefresh
。
net: bindIp: localhost,<hostname(s)|ip address(es)> port: 27018 replication: replSetName: shardA sharding: clusterRole: shardsvr
其他设置(例如 storage.dbPath
等)保持不变。
然后重启
mongod --config <path/To/ConfigFile>
如果您正在使用命令行选项
恢复到原始端口号。
包含
--replSet
.如果是一个分片成员,包含
--shardsvr
;如果是一个配置服务器成员,包含--configsvr
。删除参数
disableLogicalSessionCacheRefresh
。
例如
mongod --port 27018 --replSet shardA --shardsvr
其他设置(例如 --dbpath
等)保持不变。
允许复制在此成员上赶上。
4. 重复该步骤,为碎片剩余的二级成员执行
一旦成员赶上集合中的其他成员,依次为碎片剩余的二级成员重复此步骤
C5. 在主节点上构建索引
当碎片的二级成员都拥有新的索引时,降低碎片的主节点级别,使用上述步骤作为独立实例重新启动,并在前主节点上构建索引
使用
rs.stepDown()
方法在mongosh
中降低主节点。成功降级后,当前主节点成为二级节点,副本集成员将选举一个新的主节点。
重复操作以应用于其他受影响的分片
完成分片的索引构建后,重复C. 在包含集合块的分片上构建索引,以应用于其他受影响的分片。
E. 重启均衡器
完成受影响分片的滚动索引构建后,重启均衡器。
将mongosh
连接到分片集群中的mongos
实例,并运行sh.startBalancer()
: [3]
sh.startBalancer()
[3] | 从MongoDB 6.0.3版本开始,不再执行自动分片分割。这是因为平衡策略的改进。自动分割命令仍然存在,但不执行任何操作。在MongoDB 6.0.3之前的版本中,sh.startBalancer() 也启用了分片集群的自动拆分。 |
更多信息
分片集合如果每个包含集合数据块的分片没有完全相同的索引(包括索引选项),则具有不一致的索引。尽管在正常操作期间不应发生不一致的索引,但仍然可能发生,例如:
当用户使用具有
唯一
键约束创建索引时,且某个分片包含具有重复文档的数据块。在这种情况下,创建索引操作可能在没有重复项的分片上成功,但在有重复项的分片上失败。当用户以滚动方式跨分片创建索引,但未能为相关分片构建索引,或者以不同的规范错误地构建了索引。
配置服务器主节点定期检查分片集合跨分片索引的不一致性。要配置这些定期检查,请参阅 配置服务器,并查看 enableShardedIndexConsistencyCheck
和 shardedIndexConsistencyCheckIntervalMS
。
当在配置服务器主节点上运行时,命令 serverStatus
返回字段 shardedIndexConsistency
,以报告索引不一致。
要检查分片集合是否具有不一致的索引,请参阅 跨分片查找不一致的索引。