代码改变世界

在副本集和分片集群上构建 MongoDB 索引

2024-04-19 13:16  abce  阅读(87)  评论(0编辑  收藏  举报

1.限制

留有足够的内存来容纳工作集是非常重要的。不一定所有索引都要放在内存中。

在 v4.0 之前,索引键的限制应小于 1024 字节。从 v4.2 版开始,这一限制被取消。

索引名也是如此,在使用 fcv 4.0 及以下版本的数据库中,索引名的最大长度为 127 字节。在 db v4.2 和 fcv 4.2 中,这一限制有所减少。

任何给定的单个集合中只能创建 64 个索引。

 

2.副本集滚动构建索引

从 MongoDB 4.4 及更高版本开始,索引构建会在所有数据承载节点上同时进行。对于不能容忍索引构建导致性能问题的工作负载,我们可以采用滚动索引构建策略。

 

注:

·唯一索引

要使用以下过程创建唯一索引,必须在此过程中停止对集合的所有写入。如果无法在此过程中停止对集合的所有写入,请不要使用下面的过程。

·日志大小

确保 oplog 足够大,以便完成索引或重新索引操作,而不至于落后太多而无法赶上。

 

滚动构建的过程

(1)关闭一个辅助节点,用其它端口号,以 standalone 的方式重启。

在这一步,每次只关闭一个辅助节点。禁用配置文件中的复制参数,并将 disableLogicalSessionCacheRefresh 设置成 true:

net:
   bindIp: localhost,<hostname(s)|ip address(es)>
   port: 27217
#   port: 27017
#replication:
#   replSetName: myRepl
setParameter:
   disableLogicalSessionCacheRefresh: true

只需要做以上的调整,其它参数保持不变。完成这一步后保存退出,并重启 mongodb 实例。

sudo systemctl start mongod

现在,mongodb 运行在 27217 端口上。

(2)构建索引

登录数据库,创建索引。例如:

mongo –port 27217 -u 'username'  –authenticationDatabase admin

> use student
switched to db student

> db.studentData.createIndex( { StudentID: 1 } );
{
"createdCollectionAutomatically" : true,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}

(3)以副本集成员的方式重启该节点

索引创建结束后,就可以将该节点加回副本集了。

重新使用第一步中被注释掉的参数,重启节点。

net:
   bindIp: localhost,<hostname(s)|ip address(es)>
   port: 27017
replication:
   replSetName: myRepl

保存后重启。

sudo systemctl start mongod

这样,重启后又重新变成复制集的成员了。

(4)按照上面的步骤,重复操作剩余的辅助节点。

建议是等上一个辅助节点追上延迟后,再对下一个节点做操作。

(5)在主节点上创建索引

一旦所有辅助节点的索引构建活动结束,就使用与上述相同的流程在最后一个剩余节点上创建索引。

 

连接到主节点并发出 rs.stepDown();一旦成功降级,它就成为次节点,并选出新的主节点。按照步骤一至三建立索引即可。

3.分片集群滚动构建索引

分片集群滚动构建索引和副本集滚动构建方式类似。但是有以下不同点

(1)首先要先关闭均衡器。

为了在分片集群中以滚动方式创建索引,有必要停止均衡器,以免最终出现不一致的索引。

 

连接到 mongos 实例并运行 sh.stopBalancer() 来停用均衡器。

如果正在进行迁移,均衡器只会在正在进行的迁移完成后才会停止。

我们可以使用下面的命令检查均衡器是否已停止:

sh.getBalancerState()

如果均衡器已经被停止了,状态会是 false 。

(2)要确认集合的分布

为了以滚动的方式建立索引,有必要知道集合在哪些分片上。

连接到其中一个 mongos 并刷新缓存,这样我们就能获得要建立索引的分片内集合的最新分布信息。

 

示例:

我们要在学生数据库中的 studentData 集合中创建索引。我们将运行以下命令来获取该集合的最新分布信息。

db.adminCommand( { flushRouterConfig: "students.studentData" } );
db.records.getShardDistribution();
会获得如下类似的分片信息:
Shard shardA at shardA/s1-mongo1.net:27018,s1-mongo2.net:27018,s1-mongo3.net:27018
data : 1KiB docs : 50 chunks : 1
estimated data per chunk : 1KiB
estimated docs per chunk : 50
Shard shardC at shardC/s3-mongo1.net:27018,s3-mongo2.net:27018,s3-mongo3.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

以看出,students.studentData 存在于 shardA 和 shardC 上,我们需要分别在 shardA 和 shardC 上建立索引。

(3)以 standalone 方式启动之前,还要注释掉分片相关的参数

涉及修改端口号、注释掉复制参数、分片参数、设置 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

重启后创建索引

(4)最后要启动均衡器

sh.startBalancer()