对mongo分片集群创建索引
1. 场景
现在我们需要给大规模的mongodb集群添加索引,当集群规模巨大的时候,创建索引是一个非常可怕的操作,因为一个索引的创建的过程非常长,因为即使是稀疏索引也是需要遍历现存的所有数据的才能完成的,而且创建索引时间比较漫长的,可能在中间出现创建索引的节点宕机什么的问题;而且创建索引本身是不一个不可逆的过程,创建完之后马上删除索引是会出现很严重的问题;为此对于这个场景我们需要思考更加多一些;
2. 方案
mongo的集群模式包含有mongos + mongod replication,创建索引肯定不能直接从mongos下发,虽然从理论上可行,但是如果出现其他的没有考虑的情况的话,到时候影响面就会很巨大的;所以我们的方案基本上是这样的:
1. 一组一组shard进行创建索引的; 将db对应的primaryId对应shard放在最后去创建索引;
2. 全部完成之后再在mongos在统一创建索引;
真实创建索引是在mongod段的,所以mongos最后的创建索引是不会有任何影响,并且不会有副作用的;
2.1 知识点: 每一个db都会存在一个primary节点
在做实验的过程中,上面的第一步做完之后,从mongos段能通过getIndexes这个函数看到对应的索引,这非常奇怪,因为我本身没有对mongos进行索引创建的;最终在分析mongos的也源码发现,发现这个索引信息是去db的PrimaryId对应的shard上获得的,这个primaryId的信息要如何获得呢?
use config
db.databases.find()
//结果
{ "_id" : "test_LCC", "primary" : "shard1", "partitioned" : true }
{ "_id" : "exporter", "primary" : "shard2", "partitioned" : true }
结论: 只要对primaryId的shard创建了索引,那么mongos就能看到对应的索引;所以在创建索引的时候需要将其放在最后来创建索引,主要是为了安全性,怕遇到未知的行为;
2.2 扩容集群是否需要手动创建索引
测试结果是不需要,因为当进行movechunk的时候,mongodb会创建对应的db/coll/对应的索引
3. 预案
目前主要集中在副本集内部的创建索引的故障的场景预案上;
3.1 primary在创建索引的时候挂了怎么办
目前mongodb 副本集创建索引是primary先完成,然后secondary会并发创建索引的; 所以在当前场景下,primary挂了就切主,新的primary理论上不会知道要创建索引,而老的primary会重启然后开始恢复创建索引的进度,并且不会启动端口提供服务; 所以针对这个场景的步骤:
1. 观察新的primary是否能提供正常的服务;
2. 观察老的primary重启之后是不是在进行索引恢复过程中; 关键字为:"Index Build" 会出现类似的"Index Build (background): 235900/319691570 0%" 如果这个日志滚动中那么表示节点正在创建索引;
3. 等到老的primary创建索引成功之后,关键字为:"build index done",会有类似的日志:"build index done. scanned 324427514 total records. 4909 secs"
4. 如果老的primary创建成功之后,先去新的primary查看对应的collection是否有创建索引,正常情况是不会有的;这个时候把之前创建索引的语句在新primary重新执行
5. 观察服务的稳定性吧
3.2 primary创建成功之后,secondary并行创建过程中宕机
关于这个场景需要分开两种情况来聊:
- secondary宕机不影响majority写 ```
- 重启secondary观察创建索引的进度即可; ```
- 多个secondary出现宕机开始影响到majority写的时候 ```
- 关闭正在恢复索引的secondary
- 启动参数加入"--noIndexBuildRetry",这样让secondary忽略恢复索引的过程的;直接起来提供服务
- 等整个副本集对外写入稳定的时候,这个时候可能的情况是集群内部有几个节点存在索引,有几个节点没有的;
- 在保证副本集副本数安装的情况下,找一个有索引的副本进行锁库,然后将数据同步给其他的没有索引的节点,
- 数据同步完之后,启动;
- 最后要将"--noIndexBuildRetry"参数删除掉
##### 3.3 primary 创建索引过程中,性能影响很大的 - 切主,将主迁移到其他的节点上
- 找研发讨论后期应该如何处理
##### 3.4 primary创建成功,但是secondary并行创建的性能抖动很大的 - 选择几个secondary节点,修改启动参数,加入"--noIndexBuildRetry",然后重启;保证不会对写入有影响
- 保留一个或者多个节点进行索引创建
- 创建成功之后,通过数据copy的方式来让那些没有索引的节点也有索引 ```