铁门关市网站建设_网站建设公司_Ruby_seo优化
2026/1/10 13:26:58 网站建设 项目流程

05-MongoDB故障案例与性能优化

1、调整oplog大小引发的从库宕机

1.1 背景

  • 调整 oplog window 窗口时间后,引发了从库宕机。
  • 日志中可见从库同步失败,提示too stale to catch up

1.2 原因

延迟从库由于延迟,还未应用的 oplog 被删除(drop),导致延迟从库处于recovering状态。

1.3 解决方案

  1. 先取消延迟配置,扩容延迟从库的 oplog 大小,再扩容主库的 oplog。
  2. 对于主库,需先降级(rs.stepDown())再进行升级操作。

修改 oplog 的四种方法:

方法一(停机操作)
  1. 停掉所有 Secondary 节点。
  2. 主节点删除 local 目录下文件,副本节点删除数据目录下所有文件。
  3. 修改所有节点的配置文件,如oplogSize=1000
  4. 重启所有节点。
  5. 重新配置 replica set,副本节点重新同步数据(initial sync)。
    • 优点:操作简单。
    • 缺点:需要停服务,数据量大时同步代价高。
方法二(逐个节点替换)
  1. 移除一个 Secondary 节点,关闭服务,删除数据目录。
  2. 修改该节点配置(oplogSize=1000),启动服务。
  3. 在主节点执行rs.add()将其加入副本集。
  4. 循环上述步骤修改所有副本节点。
  5. 主节点执行rs.stepDown()降级为副本节点。
  6. 从新主节点移除该节点,并重复步骤 1-3,逐个修改每个节点。
    • 优点:无需停机。
    • 缺点:每个节点需重新同步,时间代价高。
方法三(维护模式重建 oplog - 官方推荐)
  1. 关闭 mongod(主节点先执行rs.stepDown()降级)。
  2. 修改配置文件,注释掉replSet和认证设置,修改端口。
  3. 启动实例,备份 oplog(mongodump -d local -c oplog.rs)。
  4. 进入 local 数据库,保存最新 oplog 时间点。
  5. 删除旧 oplog:db.oplog.rs.drop()
  6. 重建 oplog(如 2GB):db.runCommand({ create: "oplog.rs", capped: true, size: (2 * 1024 * 1024 * 1024) })
  7. 插入之前保存的时间点记录。
  8. 关闭实例,恢复配置文件,重启服务。
方法四(MongoDB 4.0+ 直接调整)
  1. 查看 oplog 大小:db.getReplicationInfo()
  2. 调整大小:db.adminCommand({replSetResizeOpLog:1, size:2000})
  3. 验证大小。
  4. (可选)整理碎片:db.runCommand({"compact": "oplog.rs"})

2、MongoDB最大连接数限制

  • 原因:未配置连接数或应用异常导致连接激增。
  • 最大连接数与系统max open files有关(通常为limit.rlim_cur * 0.8)。
  • 解决方法
    1. 配置net.maxIncomingConnections限制连接数。
    2. 排查应用连接异常增高的原因。

3、mongos连接数异常

  • 背景:Sharding 集群中 mongos 连接数异常,导致 ops 抖动。
  • 日志特征:大量连接被占用,连接数持续增长。
  • 解决
    • 使用net.maxIncomingConnections限制 mongos 和 mongod 的最大连接数。
    • 确保 mongod 的最大连接数大于所有 mongos 连接数之和。

4、强制重新配置副本集

  • 背景:副本集节点宕机,新节点加入后需强制重新配置。
  • 解决方法
    1. 将其中一个 Secondary 强制设为主节点:

      config=rs.conf();config.members=[config.members[2]];// 保留健康节点rs.reconfig(config,{force:true});
    2. 修复其他节点并重新加入副本集。

5、其他常见案例解决

  1. 高峰时段 chunk 迁移导致性能抖动
    配置迁移窗口时间,避免业务高峰期:

    use config;db.settings.update({_id:"balancer"},{$set:{activeWindow:{start:"02",stop:"06"}}},{upsert:true});
  2. 客户端与服务器版本不一致导致命令卡住
    保持客户端与服务器版本一致。

6、优化技巧

  1. 避免使用skip(),改用范围查询。
  2. 用简单唯一值作为_id,节省空间。
  3. 不要用文档作为_id,更新困难。
  4. 尽可能减少磁盘访问
  5. 使用索引减少内存占用
  6. 返回大量数据时避免使用索引
  7. 使用覆盖索引(Covered Index)加速查询。
  8. 使用复合索引优化多条件查询。
  9. 建立分级文档加速扫描。
  10. 查询优化
    • AND 查询:优先使用区分度最大的字段。
    • OR 查询:匹配最多的条件放在最前面。

7、用repair压缩数据库

  • 原理:相当于mongodump+mongorestore,整理数据、移除碎片。
  • 注意事项
    • 会阻塞操作,建议在热备节点执行。
    • 需要至少原数据库两倍的磁盘空间。
    • 数据量过大时,可手动使用mongodumpmongorestore替代。

8、MongoDB的使用规范

8.1 数据库的使用规范

  1. 名称必须为 UTF-8 字符,不能为空。
  2. 只能使用 ASCII 字母、数字和下划线。
  3. 建议全部小写。
  4. 长度 ≤ 64 字节。
  5. 避免使用系统库名(admin、local、config)。
  6. 建议命名规则:db_xxxx(见名知意)。

8.2 集合使用规范

  1. 名称必须为 UTF-8 字符,不能为空。
  2. 不能含空字符\0
  3. 不能以system.开头。
  4. 不能包含$字符。
  5. 长度 ≤ 64 字节。
  6. 建议只使用小写字母、下划线和点。
  7. 建议命名规则:t_xxxx
  8. 写入较大的集合建议“单库单集合”。
  9. 可使用点分隔子集合(如blog.posts)。

8.3 文档使用规范

  1. 键不能含空字符\0
  2. 键避免使用除下划线外的特殊字符。
  3. 键建议全部小写。
  4. 键不建议以数字开头。
  5. 不建议自定义_id
  6. 相似文档放同一集合。
  7. 查询条件字段值 ≤ 1KB。
  8. 大小写不敏感字段建议统一大小写。
  9. 避免用数组字段作为查询条件。
  10. 同一文档内键名不能重复。

9、MongoDB开发最佳实践

9.1 关于连接到MongoDB

  1. 驱动:选择与 MongoDB 版本兼容的驱动。
  2. 连接对象:使用单例MongoClient
  3. 连接字符串:建议在字符串中配置连接选项。
  4. 节点地址:尽可能列出所有节点。
  5. 使用域名连接:便于集群迁移,可使用mongodb+srv://协议。
  6. 避免在 mongos 前使用负载均衡:让驱动自行处理负载均衡与故障恢复。
  7. 游标使用:遍历完的游标自动关闭,未遍历完需手动close()

9.2 关于查询及索引

  • 每个查询都应有对应的索引。
  • 尽量使用覆盖索引。
  • 使用projection减少返回数据量。

9.3 关于写入

  • 更新时只包含需要更新的字段。
  • 使用批量插入提升性能。
  • 使用 TTL 自动过期日志数据。

9.4 关于文档结构

  • 避免过长的字段名。
  • 避免超过两层的数组嵌套。
  • 避免使用中文、标点等非拉丁字母作为字段名。

9.5 处理分页问题 - 避免使用 count

  • 数据量大时避免使用count()计算总页数。
  • 直接使用limit()进行分页查询。

9.6 处理分页问题 - 巧分页

  • 避免skip()/limit(),改用范围查询:
    // 第一页db.posts.find({}).sort({_id:1}).limit(20);// 第二页db.posts.find({_id:{$gt:<第一页最后一个_id>}}).sort({_id:1}).limit(20);

9.7 关于事务

  • 原则:尽量避免使用事务。
  • 优先通过模型设计规避事务。
  • 事务尽量控制在 1000 个文档更新以内。
  • 涉及事务的文档尽量分布在同一个分片上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询